//------------------------------------------------------------------------------ // // 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: CS8900ASendFrame // UINT16 CS8900ASendFrame(UINT8 *pData, UINT32 length) { BOOL rc = FALSE; UINT32 count; OALMSGS(OAL_ETHER&&OAL_VERBOSE, ( L"+CS8900ASendFrame(0x%08x, %d)\r\n", pData, length )); // Send Command OUTPORT16(&g_pCS8900->TXCMD, TX_CMD_START_ALL); OUTPORT16(&g_pCS8900->TXLENGTH, length); count = RETRY_COUNT; while (count-- > 0) { if ((ReadPacketPage(BUS_ST) & BUS_ST_TX_RDY) != 0) break; } if (count == 0) goto cleanUp; length = (length + 1) >> 1; while (length-- > 0) { OUTPORT16(&g_pCS8900->DATA0, *(UINT16*)pData); pData += sizeof(UINT16); } rc = TRUE; cleanUp: OALMSGS(OAL_ETHER&&OAL_VERBOSE, (L"-CS8900ASendFrame(rc = %d)\r\n", !rc)); return !rc; }
//------------------------------------------------------------------------------ // // 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: 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: 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: OEMMapMemAddr // // This function maps image relative address to memory address. It is used // by boot loader to verify some parts of downloaded image. // // EBOOT mapping depends on download type. Download type is // set in OMEMultiBinNotify. // UINT8* OEMMapMemAddr( DWORD image, DWORD address ) { UINT8 *pAddress = NULL; OALMSG(OAL_FUNC, (L"+OEMMapMemAddr(0x%08x, 0x%08x)\r\n", image, address)); switch (g_eboot.type) { case DOWNLOAD_TYPE_XLDR: case DOWNLOAD_TYPE_EBOOT: case DOWNLOAD_TYPE_LOGO: // Map to scratch RAM prior to flashing pAddress = (UINT8*)g_eboot.region[0].base + (address - image); break; case DOWNLOAD_TYPE_RAM: // RAM based NK.BIN and EBOOT.BIN files are given in virtual memory addresses pAddress = (UINT8*)address; break; case DOWNLOAD_TYPE_FLASHNAND: pAddress = (UINT8*) (address - NAND_ROMOFFSET); break; case DOWNLOAD_TYPE_FLASHNOR: pAddress = (UINT8*) (address - NOR_ROMOFFSET); break; #ifdef IMGMULTIXIP case DOWNLOAD_TYPE_EXT: pAddress = (UINT8*) (address); break; #endif default: OALMSG(OAL_ERROR, (L"ERROR: OEMMapMemAddr: " L"Invalid download type %d\r\n", g_eboot.type )); } OALMSGS(OAL_FUNC, (L"-OEMMapMemAddr(pAddress = 0x%08x)\r\n", pAddress)); return pAddress; }
//------------------------------------------------------------------------------ // // Function: CS8900ASendFrame // UINT16 CS8900ASendFrame(UINT8 *pData, UINT32 length) { UINT32 NumRetries; BOOL rc = TRUE; // Default to failure code OALMSGS(OAL_ETHER && OAL_VERBOSE, ( L"+CS8900ASendFrame(0x%08x, %d)\r\n", pData, length )); // Send Command OUTPORT16(&g_pCS8900->TXCMD, TX_CMD_START_ALL); OUTPORT16(&g_pCS8900->TXLENGTH, length); NumRetries = 0; while ((ReadPacketPage(BUS_ST) & BUS_ST_TX_RDY) == 0) { if (NumRetries++ >= RETRY_COUNT) { OALMSGS(OAL_ERROR, (L"ERROR: CS8900AInit: Not ready for TX\r\n")); goto Exit; } } length = (length + 1) >> 1; while (length-- > 0) { 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: OEMMultiBinNotify // VOID OEMMultiBinNotify( MultiBINInfo *pInfo ) { BOOL rc = FALSE; UINT32 base = OALVAtoPA((UCHAR*)IMAGE_WINCE_CODE_CA); UINT32 start, length; UINT32 ix; OALMSGS(OAL_FUNC, ( L"+OEMMultiBinNotify(0x%08x -> %d)\r\n", pInfo, pInfo->dwNumRegions )); OALMSG(OAL_INFO, ( L"Download file information:\r\n" )); OALMSG(OAL_INFO, ( L"-----------------------------------------------------------\r\n" )); // Copy information to EBOOT structure and set also save address g_eboot.numRegions = pInfo->dwNumRegions; for (ix = 0; ix < pInfo->dwNumRegions; ix++) { g_eboot.region[ix].start = pInfo->Region[ix].dwRegionStart; g_eboot.region[ix].length = pInfo->Region[ix].dwRegionLength; g_eboot.region[ix].base = base; base += g_eboot.region[ix].length; OALMSG(OAL_INFO, ( L"[%d]: Address=0x%08x Length=0x%08x Save=0x%08x\r\n", ix, g_eboot.region[ix].start, g_eboot.region[ix].length, g_eboot.region[ix].base )); } OALMSG(OAL_INFO, ( L"-----------------------------------------------------------\r\n" )); // Determine type of image downloaded if (g_eboot.numRegions > 1) { OALMSG(OAL_ERROR, (L"ERROR: MultiXIP image is not supported\r\n")); goto cleanUp; } base = g_eboot.region[0].base; start = g_eboot.region[0].start; length = g_eboot.region[0].length; if (start == IMAGE_XLDR_CODE_PA) { g_eboot.type = DOWNLOAD_TYPE_XLDR; memset(OALPAtoCA(base), 0xFF, length); } else if (start == IMAGE_EBOOT_CODE_CA) { g_eboot.type = DOWNLOAD_TYPE_EBOOT; memset(OALPAtoCA(base), 0xFF, length); } else if (start == (IMAGE_WINCE_CODE_CA + NAND_ROMOFFSET)) { g_eboot.type = DOWNLOAD_TYPE_FLASHNAND; memset(OALPAtoCA(base), 0xFF, length); } else if (start == (IMAGE_WINCE_CODE_CA + NOR_ROMOFFSET)) { g_eboot.type = DOWNLOAD_TYPE_FLASHNOR; memset(OALPAtoCA(base), 0xFF, length); } else if (start == 0) // Probably a NB0 file, let's fint out { // Convert the file name to lower case CHAR szFileName[MAX_PATH]; int i = 0; int fileExtPos = 0; while ((pInfo->Region[0].szFileName[i] != '\0') && (i < MAX_PATH)) { if((pInfo->Region[0].szFileName[i] >= 'A') && (pInfo->Region[0].szFileName[i] <= 'Z')) { szFileName[i] = (pInfo->Region[0].szFileName[i] - 'A' + 'a'); } else { szFileName[i] = pInfo->Region[0].szFileName[i]; } // Keep track of file extension position if (szFileName[i] == '.') { fileExtPos = i; } i++; } // Copy string terminator as well szFileName[i] = pInfo->Region[0].szFileName[i]; // Check if we support this file if (strncmp(szFileName, LOGO_NB0_FILE, LOGO_NB0_FILE_LEN) == 0) { // Remap the start address to the correct NAND location of the logo g_eboot.region[0].start = IMAGE_XLDR_BOOTSEC_NAND_SIZE + IMAGE_EBOOT_BOOTSEC_NAND_SIZE; g_eboot.type = DOWNLOAD_TYPE_LOGO; } else { OALMSG(OAL_ERROR, (L"Unsupported downloaded file\r\n")); goto cleanUp; } } else { g_eboot.type = DOWNLOAD_TYPE_RAM; } OALMSG(OAL_INFO, ( L"Download file type: %d\r\n", g_eboot.type )); rc = TRUE; cleanUp: if (!rc) { OALMSG(OAL_ERROR, (L"Spin for ever...\r\n")); for(;;); } OALMSGS(OAL_FUNC, (L"-OEMMultiBinNotify\r\n")); }
//------------------------------------------------------------------------------ // // 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; }