//------------------------------------------------------------------------------ // // 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); }
//------------------------------------------------------------------------------ // // Function: CS8900ADisableInts // VOID CS8900ADisableInts() { 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: CS8900AGetFrame // UINT16 CS8900AGetFrame(UINT8 *pData, UINT16 *pLength) { UINT16 isq, length, status, count, data; OALMSGS(OAL_ETHER&&OAL_VERBOSE, ( L"+CS8900AGetFrame(0x%08x, %d)\r\n", pData, *pLength )); 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); count -= sizeof(UINT16); } // Read last one byte if (count > 0) { data = INPORT16(&g_pCS8900->DATA0); *pData = (UINT8)data; } } } // Return packet size *pLength = length; OALMSGS(OAL_ETHER&&OAL_VERBOSE, ( L"-CS8900AGetFrame(length = %d)\r\n", length )); return length; }
//------------------------------------------------------------------------------ // // 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: CS8900AInit // BOOL CS8900AInit(UINT8 *pAddress, UINT32 offset, UINT16 mac[3]) { UINT32 NumRetries; PBYTE pBaseIOAddress = NULL; UINT32 MemoryBase = 0; BOOL rc = FALSE; OALMSGS(OAL_ETHER && OAL_FUNC, ( L"+CS8900AInit(0x%08x, 0x%08x, %02x:%02x:%02x:%02x:%02x:%02x)\r\n", pAddress, offset, mac[0]&0xFF, mac[0]>>8, mac[1]&0xFF, mac[1]>>8, mac[2]&0xFF, mac[2]>>8 )); // Save address g_pCS8900 = (CS8900A_REGS*)pAddress; // First check if there is chip if (ReadPacketPage(EISA_NUMBER) != CS8900A_EISA_NUMBER) { OALMSGS(OAL_ERROR, (L"ERROR: CS8900AInit: Failed detect chip\r\n")); goto Exit; } OALMSGS(OAL_INFO, (L"INFO: CS8900AInit chip detected\r\n")); // Initiate a reset sequence in software. WritePacketPage(SELF_CTL, SELF_CTL_RESET); // Wait for status to indicate initialization is complete. NumRetries = 0; while ((ReadPacketPage(SELF_ST) & SELF_ST_INITD) == 0) { if (NumRetries++ >= RETRY_COUNT) { OALMSGS(OAL_ERROR, (L"ERROR: CS8900AInit: Timed out during initialization\r\n")); goto Exit; } } // Wait for status to indicate the EEPROM is done being accessed/programmed. NumRetries = 0; while ((ReadPacketPage(SELF_ST) & SELF_ST_SIBUSY) != 0) { if (NumRetries++ >= RETRY_COUNT) { OALMSGS(OAL_ERROR, (L"ERROR: CS8900AInit: Timed out (EEPROM stayed busy)\r\n")); goto Exit; } } pBaseIOAddress = (PBYTE)OALPAtoVA(pBSPArgs->kitl.devLoc.LogicalLoc, FALSE); MemoryBase = (UINT32)OALPAtoVA(BSP_BASE_REG_PA_CS8900A_MEMBASE, FALSE); // Initialize the Ethernet controller, set MAC address // if (!CS8900DBG_Init((PBYTE)pBaseIOAddress, MemoryBase, mac)) { OALMSG(OAL_ERROR, (TEXT("ERROR: InitEthDevice: Failed to initialize Ethernet controller.\r\n"))); goto Exit; } // Enable receive WritePacketPage(RX_CTL, RX_CTL_RX_OK | RX_CTL_INDIVIDUAL | RX_CTL_BROADCAST); // Enable interrupt on receive WritePacketPage(RX_CFG, RX_CFG_RX_OK_IE); // Configure the hardware to use INTRQ0 WritePacketPage(INTERRUPT_NUMBER, 0); // Enable WritePacketPage(LINE_CTL, LINE_CTL_RX_ON | LINE_CTL_TX_ON); // Make sure MAC address has been programmed. // if (!pBSPArgs->kitl.mac[0] && !pBSPArgs->kitl.mac[1] && !pBSPArgs->kitl.mac[2]) { OALMSG(OAL_ERROR, (TEXT("ERROR: InitEthDevice: Invalid MAC address.\r\n"))); goto Exit; } // Done rc = TRUE; Exit: OALMSGS(OAL_ETHER && OAL_FUNC, (L"-CS8900AInit(rc = %d)\r\n", rc)); return rc; }
//------------------------------------------------------------------------------ // // Function: CS8900AInit // BOOL CS8900AInit(UINT8 *pAddress, UINT32 offset, UINT16 mac[3]) { BOOL rc = FALSE; UINT32 count; OALMSGS(OAL_ETHER&&OAL_FUNC, ( L"+CS8900AInit(0x%08x, 0x%08x, %02x:%02x:%02x:%02x:%02x:%02x)\r\n", pAddress, offset, mac[0]&0xFF, mac[0]>>8, mac[1]&0xFF, mac[1]>>8, mac[2]&0xFF, mac[2]>>8 )); // Save address g_pCS8900 = (CS8900A_REGS*)pAddress; // First check if there is chip if (ReadPacketPage(EISA_NUMBER) != CS8900A_EISA_NUMBER) { OALMSGS(OAL_ERROR, (L"ERROR: CS8900AInit: Failed detect chip\r\n")); goto cleanUp; } OALMSGS(OAL_INFO, (L"INFO: CS8900AInit chip detected\r\n")); // Reset chip WritePacketPage(SELF_CTL, SELF_CTL_RESET); count = RETRY_COUNT; while (count-- > 0) { if ((ReadPacketPage(SELF_ST) & SELF_ST_INITD) != 0) break; } if (count == 0) { OALMSGS(OAL_ERROR, (L"ERROR: CS8900AInit: Failed to reset card\r\n")); goto cleanUp; } count = RETRY_COUNT; while (count-- > 0) { if ((ReadPacketPage(SELF_ST) & SELF_ST_SIBUSY) != 0) break; } if (count == 0) { OALMSGS(OAL_ERROR, (L"ERROR: CS8900AInit: Failed to reset card\r\n")); goto cleanUp; } // Set MAC address WritePacketPage(INDIVIDUAL_ADDRESS + 0, mac[0]); WritePacketPage(INDIVIDUAL_ADDRESS + 2, mac[1]); WritePacketPage(INDIVIDUAL_ADDRESS + 4, mac[2]); // Enable receive WritePacketPage(RX_CTL, RX_CTL_RX_OK|RX_CTL_INDIVIDUAL|RX_CTL_BROADCAST); // Enable interrupt on receive WritePacketPage(RX_CFG, RX_CFG_RX_OK_IE); // Let assume that hardware is using INTRQ0 WritePacketPage(INTERRUPT_NUMBER, 0); // Enable WritePacketPage(LINE_CTL, LINE_CTL_RX_ON|LINE_CTL_TX_ON); // Done rc = TRUE; cleanUp: OALMSGS(OAL_ETHER&&OAL_FUNC, (L"-CS8900AInit(rc = %d)\r\n", rc)); return rc; }