//************************************************************** //************************************************************** //********** TRANSMIT THE PACKET IN THE NIC TX BUFFER ********** //************************************************************** //************************************************************** void nix_tx_packet (void) { //----------------------------------------------------------- //----- IF PACKET IS BELOW MINIMUM LENGTH ADD PAD BYTES ----- //----------------------------------------------------------- while (nic_tx_len < 60) { nic_write_next_byte(0x00); } //-------------------------------- //----- ADD THE ETHERNET CRC ----- //-------------------------------- //No need - the nic does this for us //------------------------------------------------------------------ //----- ADD THE CONTROL BYTE AND THE FINAL ODD BYTE IF PRESENT ----- //------------------------------------------------------------------ if (nic_tx_next_byte_is_odd_byte) { nic_write(NIC_REG_DATA, 0x0000); } else { nic_write(NIC_REG_DATA, ((nic_tx_next_byte_next_data_word & 0xff) | 0x2000)); nic_tx_len--; //(Decrement as the final odd byte is included below) } //------------------------------------------------- //----- WRITE THE TOTAL NUMBER OF BYTES TO TX ----- //------------------------------------------------- //Setup the pointer register for a data write to the tx memory buffer while(nic_read(NIC_REG_POINTER) & 0x0800) //Check the data write FIFO is empty before writing to the pointer register ; nic_write(NIC_REG_POINTER, (0x4000 + 2)); //+2 to offset to the BYTE COUNT register //Write the tx byte count nic_write(NIC_REG_DATA, (nic_tx_len + 6)); //(+6 nic bytes: status[2], byte count [2], control byte[1], last data byte[1]) //--------------------------- //----- SEND THE PACKET ----- //--------------------------- //Ensure MMU isn't busy while (nic_read(NIC_REG_MMU_COMMAND) & 0x0001) ; //Send 'ENQUEUE PACKET NUMBER TO TX FIFO' MMU Command nic_write(NIC_REG_MMU_COMMAND, 0x00c0); return; }
//********************************** //********************************** //********** NIC SETUP TX ********** //********************************** //********************************** //Checks the nic to see if it is ready to accept a new tx packet. If so it sets up the nic ready for the first byte of the data area to be sent. //Returns 1 if nic ready, 0 if not. BYTE nic_setup_tx (void) { //----- CHECK THE NIC ISN'T OVERFLOWED ----- //(can happen if nic processing has been stopped for a length of time by other application processes) //Set nic page 0 nic_write(NIC_REG_CR, 0x20); //Read the interrupt status register if (nic_read(NIC_REG_ISR) & 0x10) { //Overflow has occured nic_rx_overflow_clear(); } //----- EXIT IF NIC IS STILL DOING LAST TX ----- //Stop dma and set page 0 nic_write(NIC_REG_CR, 0x22); //Is nic tx still busy from last tx? if (nic_read(NIC_REG_CR) & 0x04) return(0); //----- ABORT ANY DMA CURRENTLY ACTIVE ----- nic_write(NIC_REG_CR, 0x20); //Wait for DMA to complete //while ((nic_read(NIC_REG_ISR) & 0x40 == 0)); //Set no of bytes to transmit to nic via dma (dummy value) nic_write(NIC_REG_RBCR0, (BYTE)(1536 & 0x00ff)); nic_write(NIC_REG_RBCR1, (BYTE)(1536 >> 8)); //Set remote DMA address to write to nic_write(NIC_REG_CRDA0, 0x00); nic_write(NIC_REG_CRDA1, NIC_TX_START_LOC_IN_RING); //Set remote write nic_write(NIC_REG_CR, 0x12); //Set the address to DMA nic_write_address(NIC_REG_REM_DMA); nic_tx_len = 0; //Next byte is the 1st byte of the Ethernet Frame return(1); }
//************************************** //************************************** //********** NIC MOVE POINTER ********** //************************************** //************************************** //Moves the pointer to a specified byte ready to be read next, with a value of 0 = the first byte of the Ethernet header void nic_move_pointer (WORD move_pointer_to_ethernet_byte) { WORD new_pointer_value; BYTE dummy_data; //Set nic bank 2 nic_write(NIC_REG_BANK, 0x3302); //Data pointer register while(nic_read(NIC_REG_POINTER) & 0x0800) //Check the data write FIFO is empty before writing to the pointer register ; //----- SET THE NEW ADDRESS ----- new_pointer_value = ((move_pointer_to_ethernet_byte + 4) & 0x07fe); //Needs to be word aligned - low bit dealt with later, +4 to move past the nic status word and byte count new_pointer_value |= 0xe000; //RCV, AUTO INC & READ bits set nic_write(NIC_REG_POINTER, new_pointer_value); nic_read_next_byte_get_word = 1; //Set the address ready for data read nic_write_address(NIC_REG_DATA); //If new pointer value is odd then read the first byte of the new word if (move_pointer_to_ethernet_byte & 0x0001) nic_read_next_byte(&dummy_data); //ADDRESSED BYTE IS NOW READY TO BE READ //----- ADJUST THE NIC DATA BYTES REMAINING COUNT ----- nic_rx_bytes_remaining = nic_rx_packet_total_ethernet_bytes - move_pointer_to_ethernet_byte; }
//********************************************************* //********************************************************* //********** NIC WRITE WORD AT SPECIFIC LOCATION ********** //********************************************************* //********************************************************* //byte_address must be word aligned void nic_write_tx_word_at_location (WORD byte_address, WORD data) { WORD_VAL last_pointer_value; WORD_VAL pointer_value; //Set page 0 and abort any active DMA nic_write(NIC_REG_CR, 0x21); //Wait for DMA to complete //while ((nic_read(NIC_REG_ISR) & 0x40 == 0)); //GET THE CURRENT POINTER LOCATION last_pointer_value.v[0] = nic_read(NIC_REG_CRDA0); last_pointer_value.v[1] = nic_read(NIC_REG_CRDA1); //MOVE THE POINTER TO THE REQUESTED WORD ADDRESS pointer_value.Val = (((WORD)NIC_TX_START_LOC_IN_RING << 8) + (WORD)byte_address); nic_write(NIC_REG_RSAR0, pointer_value.v[0]); nic_write(NIC_REG_RSAR1, pointer_value.v[1]); //Set number of bytes to write nic_write(NIC_REG_RBCR0, 2); nic_write(NIC_REG_RBCR1, 0); //Set remote write nic_write(NIC_REG_CR, 0x12); //WRITE THE WORD nic_write(NIC_REG_REM_DMA, (BYTE)(data & 0x00ff)); nic_write(NIC_REG_REM_DMA, (BYTE)(data >> 8)); //Write a dummy value to the number of bytes to be written nic_write(NIC_REG_RBCR0, (BYTE)(1536 & 0x00ff)); nic_write(NIC_REG_RBCR1, (BYTE)(1536 >> 8)); //RESTORE POINTER TO PREVIOUS LOCATION nic_write(NIC_REG_RSAR0, last_pointer_value.v[0]); nic_write(NIC_REG_RSAR1, last_pointer_value.v[1]); //Set remote write nic_write(NIC_REG_CR, 0x12); //Set the address to DMA nic_write_address(NIC_REG_REM_DMA); }
static int NicReset(void) { volatile uint8_t *base = nic_base; uint8_t i; uint8_t j; /* Start command clears the reset bit. */ nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD2); //printf("[%02X]", nic_read(NIC_PG0_ISR)); for (j = 0; j < 20; j++) { printf("SW-Reset..."); i = nic_read(NIC_RESET); Delay(500); nic_write(NIC_RESET, i); for (i = 0; i < 20; i++) { //Delay(5000); /* * ID detection added for version 1.1 boards. */ if ((nic_read(NIC_PG0_ISR) & NIC_ISR_RST) != 0 && nic_read(NIC_PG0_RBCR0) == 0x50 && nic_read(NIC_PG0_RBCR1) == 0x70) { puts("OK"); return 0; } } puts("failed\x07"); /* * Toggle the hardware reset line. Since Ethernut version 1.3 the * hardware reset pin of the nic is no longer connected to bit 4 * on port E, but wired to the board reset line. */ if (j == 10) { puts("HW-Reset"); #if defined (__AVR__) sbi(DDRE, 4); sbi(PORTE, 4); Delay(100000); cbi(PORTE, 4); Delay(250000); #endif } } return -1; }
static int NicReset(void) { volatile unsigned char *base = (unsigned char *)0x8300; unsigned char i; unsigned char j; for(j = 0; j < 20; j++) { debug_print(PSTR("SW-Reset...")); i = nic_read(NIC_RESET); Delay(500); nic_write(NIC_RESET, i); for(i = 0; i < 20; i++) { Delay(5000); /* * ID detection added for version 1.1 boards. */ if((nic_read(NIC_PG0_ISR) & NIC_ISR_RST) != 0 && nic_read(NIC_PG0_RBCR0) == 0x50 && nic_read(NIC_PG0_RBCR1) == 0x70) { debug_print(PSTR("OK\r\n")); return 0; } } debug_print(PSTR("failed\r\n\x07")); /* * Toggle the hardware reset line. Since Ethernut version 1.3 the * hardware reset pin of the nic is no longer connected to bit 4 * on port E, but wired to the board reset line. */ if(j == 10) { debug_print(PSTR("Ethernut 1.1 HW-Reset\r\n")); sbi(DDRE, 4); sbi(PORTE, 4); Delay(100000); cbi(PORTE, 4); Delay(250000); } } return -1; }
//************************************************************* //************************************************************* //********** NIC RECEIVE OVERFLOW - CLEAR RX BUFFERS ********** //************************************************************* //************************************************************* void nic_rx_overflow_clear (void) { nic_rx_packet_waiting_to_be_dumped = 0; //----- READ THE RX FIFO ----- //Set nic bank 2 nic_write(NIC_REG_BANK, 0x3302); //Get the Fifo Register while ((nic_read(NIC_REG_FIFO_PORTS) & 0x8000) == 0) //Is there a packet waiting (REMPTY bit 15 = 0)? { //----- THERE IS A PACKET WAITING ----- //Setup the data pointer register to read the rx packet while(nic_read(NIC_REG_POINTER) & 0x0800) //Check the data write FIFO is empty before writing to the pointer register ; nic_write(NIC_REG_POINTER, 0xe000); //RCV, AUTO INC & READ bits set //Get the rx status and byte count //(Read the data register to get the packet) nic_read(NIC_REG_DATA); //Dump the packet nic_rx_dump_packet(); //Set nic bank 2 (ready for next read of Fifo) nic_write(NIC_REG_BANK, 0x3302); } //----- ALL DONE - CLEAR THE OVERFLOW IRQ FLAG ----- //Set nic bank 2 (ready for next read of Fifo) //nic_write(NIC_REG_BANK, 0x3302); //Clear the RX_OVR bit if set nic_write(NIC_REG_INTERRUPT, (NIC_CONST_IRQ_REGISTER | 0x0010)); //(little endian) }
//**************************************** //**************************************** //********** NIC DUMP RX PACKET ********** //**************************************** //**************************************** //Discard any remaining bytes in the current RX packet and free up the nic for the next rx packet void nic_rx_dump_packet (void) { //Set nic bank 2 nic_write(NIC_REG_BANK, 0x3302); //Ensure MMU isn't busy while (nic_read(NIC_REG_MMU_COMMAND) & 0x0001) ; //Send 'Remove and Release From Top Of RX' MMU Command nic_write(NIC_REG_MMU_COMMAND, 0x0080); nic_rx_packet_waiting_to_be_dumped = 0; }
//************************************************ //************************************************ //********** NIC SETUP READ DATA BUFFER ********** //************************************************ //************************************************ void nic_setup_read_data (void) { //Set nic bank 2 nic_write(NIC_REG_BANK, 0x3302); //Data pointer register while(nic_read(NIC_REG_POINTER) & 0x0800) //Check the data write FIFO is empty before writing to the pointer register ; nic_write(NIC_REG_POINTER, 0xe000); //RCV, AUTO INC & READ bits set nic_read_next_byte_get_word = 1; //Set the address nic_write_address(NIC_REG_DATA); //Next operation can read the nic and data will be transfered from the data buffer }
//********************************************************* //********************************************************* //********** NIC WRITE WORD AT SPECIFIC LOCATION ********** //********************************************************* //********************************************************* //byte_address must be word aligned void nic_write_tx_word_at_location (WORD byte_address, WORD data) { WORD last_pointer_value; WORD pointer_value; //GET THE CURRENT POINTER LOCATION last_pointer_value = 0x0800; while (last_pointer_value & 0x0800) //NOT EMPTY bit must be low last_pointer_value = nic_read(NIC_REG_POINTER); //MOVE THE POINTER TO THE REQUESTED WORD ADDRESS pointer_value = ((last_pointer_value & 0xf800) + byte_address + 4); //+4 to get past Status and Byte count nic words before the data nic_write(NIC_REG_POINTER, pointer_value); nic_write(NIC_REG_DATA, data); //RESTORE POINTER TO PREVIOUS LOCATION nic_write(NIC_REG_POINTER, last_pointer_value); nic_write_address(NIC_REG_DATA); }
//***************************************** //***************************************** //********** READ NIC LINK SETUP ********** //***************************************** //***************************************** //Returns: // Bit 0 = high for 100Base-T speed, low for 10Base-T speed // Bit 1 = high for full duplex, low for half duplex BYTE nic_read_link_setup (void) { WORD data; BYTE return_status = 0; //----- READ THE LINK STATUS REGISTER FROM THE PHY ----- //Dummy read (it doesn't load the correct value the first time) nic_read_phy_register (NIC_PHY_STATUS_OUTPUT); //Read the status output register data = nic_read_phy_register (NIC_PHY_STATUS_OUTPUT); if (data & 0x0080) { //HIGH SPEED return_status |= 0x01; } if (data & 0x0040) { //FULL DUPLEX return_status |= 0x02; } //----- SETUP THE TX REGISTER TO MATCH THE LINK STATUS ----- //Set bank 0 nic_write(NIC_REG_BANK, 0x3300); //Get the Transmit Control Register data = nic_read(NIC_REG_TCR); //If DPLXDET (full duplex) was set then the TX reg SWFDUP bit (15) must be set data &= 0x7fff; if (return_status & 0x02) data |= 0x8000; //Re-write the transmit Control register nic_write(NIC_REG_TCR, data); return (return_status); }
//********************************** //********************************** //********** NIC SETUP TX ********** //********************************** //********************************** //Checks the nic to see if it is ready to accept a new tx packet. If so it sets up the nic ready for the first byte of the data area to be sent. //Returns 1 if nic ready, 0 if not. BYTE nic_setup_tx (void) { WORD data; //----- CHECK THE NIC ISN'T OVERFLOWED ----- //(can happen if nic processing has been stopped for a length of time by other application processes) //Set nic bank 2 nic_write(NIC_REG_BANK, 0x3302); //Read the irq register //(If rx overrun bit is set then we need to clear it as the nic locks until we do) if (nic_read(NIC_REG_INTERRUPT) & 0x0010) { //Overflow has occured nic_rx_overflow_clear(); } //Send the allocate memory for tx command to the nic //Set nic bank 2 nic_write(NIC_REG_BANK, 0x3302); //Ensure MMU isn't busy while (nic_read(NIC_REG_MMU_COMMAND) & 0x0001) ; //MMU Command //(Allocate memory for TX) nic_write(NIC_REG_MMU_COMMAND, 0x0020); //Wait for MMU busy flag to clear while (nic_read(NIC_REG_MMU_COMMAND) & 0x0001) ; //Wait for the ALLOC INT bit to be set while (1) { //Set nic bank 2 //nic_write(NIC_REG_BANK, 0x3302); data = nic_read(NIC_REG_INTERRUPT); //Check for overflow - If rx overrun bit is set then we need to clear it as the nic locks until we do if (data & 0x0010) return(0); //Clear will happen next time //ALLOC INT bit set? if (data & 0x0008) break; } //Read the allocation result register data = nic_read(NIC_REG_PNR); if (data & 0x8000) //(Little endian) { //----- ALLOCATION FAILED - NO TX SPACE CURRENTLY AVAILABLE ----- return(0); } data &= 0xff00; //Copy the allocation packet number data |= (data >> 8); //-------------------------------------------- //----- ALLOCATION SUCCESSFUL - SETUP TX ----- //-------------------------------------------- //Setup the packet number register with the obtained allocation packet number nic_write(NIC_REG_PNR, data); //Setup the pointer register for a data write to the tx memory buffer while(nic_read(NIC_REG_POINTER) & 0x0800) //Check the data write FIFO is empty before writing to the pointer register ; nic_write(NIC_REG_POINTER, 0x4000); //AUTO INC bit set, RCV & READ bits not set //Set the address nic_write_address(NIC_REG_DATA); nic_tx_len = 0; nic_tx_next_byte_is_odd_byte = 1; //Write the status word to the data register (word 0) nic_write_next_byte(0x00); nic_write_next_byte(0x00); //Send number of bytes to tx (zero for now - we re-write this at the end) nic_write_next_byte(0x00); nic_write_next_byte(0x00); //Next byte is the 1st byte of the Ethernet Frame nic_tx_len = 0; return(1); }
void RealtekSend(void) { uint8_t mac[] = { 0x00, 0x06, 0x98, 0x00, 0x00, 0x00 }; uint16_t sz; uint16_t i; volatile uint8_t *base = nic_base; uint8_t rb; uint32_t cnt = 0; printf("Init controller..."); nic_write(NIC_PG0_IMR, 0); nic_write(NIC_PG0_ISR, 0xff); if (NicReset()) return; printf(" detecting..."); Delay(200000); if (DetectNicEeprom() == 0) { printf("EEPROM Emulation..."); EmulateNicEeprom(); } nic_write(NIC_CR, NIC_CR_STP | NIC_CR_RD2 | NIC_CR_PS0 | NIC_CR_PS1); nic_write(NIC_PG3_EECR, NIC_EECR_EEM0 | NIC_EECR_EEM1); nic_write(NIC_PG3_CONFIG3, 0); nic_write(NIC_PG3_CONFIG2, NIC_CONFIG2_BSELB); nic_write(NIC_PG3_EECR, 0); Delay(50000); nic_write(NIC_CR, NIC_CR_STP | NIC_CR_RD2); nic_write(NIC_PG0_DCR, NIC_DCR_LS | NIC_DCR_FT1); nic_write(NIC_PG0_RBCR0, 0); nic_write(NIC_PG0_RBCR1, 0); nic_write(NIC_PG0_RCR, NIC_RCR_MON); nic_write(NIC_PG0_TCR, NIC_TCR_LB0); nic_write(NIC_PG0_TPSR, NIC_FIRST_TX_PAGE); nic_write(NIC_PG0_BNRY, NIC_STOP_PAGE - 1); nic_write(NIC_PG0_PSTART, NIC_FIRST_RX_PAGE); nic_write(NIC_PG0_PSTOP, NIC_STOP_PAGE); nic_write(NIC_PG0_ISR, 0xff); nic_write(NIC_CR, NIC_CR_STP | NIC_CR_RD2 | NIC_CR_PS0); for (i = 0; i < 6; i++) nic_write(NIC_PG1_PAR0 + i, mac[i]); for (i = 0; i < 8; i++) nic_write(NIC_PG1_MAR0 + i, 0); nic_write(NIC_PG1_CURR, NIC_START_PAGE + TX_PAGES); nic_write(NIC_CR, NIC_CR_STP | NIC_CR_RD2); nic_write(NIC_PG0_RCR, NIC_RCR_AB); nic_write(NIC_PG0_ISR, 0xff); nic_write(NIC_PG0_IMR, 0); nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD2); nic_write(NIC_PG0_TCR, 0); Delay(1000000); puts("done"); nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD2 | NIC_CR_PS0 | NIC_CR_PS1); rb = nic_read(NIC_PG3_CONFIG0); switch (rb & 0xC0) { case 0x00: printf("RTL8019AS "); if (rb & 0x08) printf("jumper mode: "); if (rb & 0x20) printf("AUI "); if (rb & 0x10) printf("PNP "); break; case 0xC0: printf("RTL8019 "); if (rb & 0x08) printf("jumper mode: "); break; default: printf("Unknown chip "); break; } if (rb & 0x04) printf("BNC\x07 "); if (rb & 0x03) printf("Failed\x07 "); rb = nic_read(NIC_PG3_CONFIG1); printf("IRQ%u ", (rb >> 4) & 7); rb = nic_read(NIC_PG3_CONFIG2); switch (rb & 0xC0) { case 0x00: printf("Auto "); break; case 0x40: printf("10BaseT "); break; case 0x80: printf("10Base5 "); break; case 0xC0: printf("10Base2 "); break; } printf("\n"); nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD2); for (;;) { Delay(500000); printf("\r%lu", cnt++); sz = 1500; nic_write(NIC_PG0_RBCR0, sz); nic_write(NIC_PG0_RBCR1, sz >> 8); nic_write(NIC_PG0_RSAR0, 0); nic_write(NIC_PG0_RSAR1, NIC_FIRST_TX_PAGE); nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD1); /* * Transfer ethernet physical header. */ for (i = 0; i < 6; i++) nic_write(NIC_IOPORT, 0xFF); for (i = 0; i < 6; i++) nic_write(NIC_IOPORT, mac[i]); nic_write(NIC_IOPORT, 0x08); nic_write(NIC_IOPORT, 0x00); /* * Add pad bytes. */ for (i = 0; i < sz; i++) nic_write(NIC_IOPORT, 0); /* * Complete remote dma. */ nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD2); for (i = 0; i <= 20; i++) if (nic_read(NIC_PG0_ISR) & NIC_ISR_RDC) break; nic_write(NIC_PG0_ISR, NIC_ISR_RDC); /* * Number of bytes to be transmitted. */ nic_write(NIC_PG0_TBCR0, (sz & 0xff)); nic_write(NIC_PG0_TBCR1, ((sz >> 8) & 0xff)); /* * First page of packet to be transmitted. */ nic_write(NIC_PG0_TPSR, NIC_FIRST_TX_PAGE); /* * Start transmission. */ nic_write(NIC_CR, NIC_CR_STA | NIC_CR_TXP | NIC_CR_RD2); if (GetChar()) break; Delay(10000); } }
//************************************ //************************************ //********** INITIALISE NIC ********** //************************************ //************************************ //Call with: //init_config = don't care (speed configuration options not available with this IC) void nic_initialise (BYTE init_config) { //----------------------------- //----- DO HARDWARE RESET ----- //----------------------------- nic_delay_ms(10); //RESET THE NIC nic_reset(); nic_delay_ms(50); //Wait for reset bit to be set while((nic_read(NIC_REG_ISR) & 0x80) == 0); //------------------------------------------------- //----- WRITE THE NIC CONFIGURATION REGISTERS ----- //------------------------------------------------- //As the nic doesn't have its own eeprom we need to setup the bank3 config registers //Note that the DO pin of where the eeprom would be connected must be pulled low. //Config 1 and 2 are not altered by the eeprom change as in jumper mode they use the default state of defined pins //Config 3 is affected by the eeprom and contains several bits that are read only (i.e. can only be set by the eeprom). The important pin //is the FUDUP pin which must be low, or the nic looses transmissions by assuming that it can tx while rx is active. This means that the //LED control pins also have to be low. Ideally the LED pins would be high as it gives the more useful 'Link' and 'Active' led outptus, //but this is the compromise. //Stop DMA and Set page 3 nic_write(NIC_REG_CR, 0xe1); //Enable writing to the config registers nic_write(NIC_REG_9346CR, 0xc0); //Config 0 is read only //nic_write(NIC_REG_CONFIG0, 0x); //Disable IRQ's (rest is set by jumpers) nic_write(NIC_REG_CONFIG1, 0x00); //Set network medium type nic_write(NIC_REG_CONFIG2, 0x00); //Set not in sleep mode, not in powerdown mode nic_write(NIC_REG_CONFIG3, 0x30); //Disable writing to the config registers nic_write(NIC_REG_9346CR, 0x00); nic_delay_ms(50); //Set page 0 nic_write(NIC_REG_CR, 0x21); //Setup the the Data Configuration Register (DCR) nic_write(NIC_REG_DCR, 0x58); //Clear the remote byte count registers nic_write(NIC_REG_RBCR0, 0x00); nic_write(NIC_REG_RBCR1, 0x00); //Initialise the receive configuration register (monitor mode) nic_write(NIC_REG_RCR, 0x20); //Turn on loopback mode nic_write(NIC_REG_TCR, 0x02); //Initialise the receive buffer ring //RTL8019AS has 16K bytes of ram //Tx buffer starts at 0x4000 //Rx ring starts / tx buffer ends at 0x0x4600 - this gives 1536 bytes to tx, max tx size allowed on ethernet is 1500 bytes. //Rx ring ends at 0x6000 - this gives 6656 bytes to rx (used in 256 byte pages by nic) nic_write(NIC_REG_BNDRY, NIC_RX_START_LOC_IN_RING); nic_write(NIC_REG_PSTART, NIC_RX_START_LOC_IN_RING); nic_write(NIC_REG_PSTOP, NIC_RX_END_LOC_IN_RING); //Clear the Interrupt Status Register nic_write(NIC_REG_ISR, 0xff); //Initialise the interrupt mask register (all irq's disabled) nic_write(NIC_REG_IMR, 0x00); //Stop DMA and Set page 1 nic_write(NIC_REG_CR, 0x61); //Set the MAC address in the nic registers nic_write(NIC_REG_PAR0, our_mac_address.v[0]); nic_write(NIC_REG_PAR1, our_mac_address.v[1]); nic_write(NIC_REG_PAR2, our_mac_address.v[2]); nic_write(NIC_REG_PAR3, our_mac_address.v[3]); nic_write(NIC_REG_PAR4, our_mac_address.v[4]); nic_write(NIC_REG_PAR5, our_mac_address.v[5]); //Initialise the multicast address registers //Set all MARx to 0 = reject all multicast nic_write(NIC_REG_MAR0, 0x00); nic_write(NIC_REG_MAR1, 0x00); nic_write(NIC_REG_MAR2, 0x00); nic_write(NIC_REG_MAR3, 0x00); nic_write(NIC_REG_MAR4, 0x00); nic_write(NIC_REG_MAR5, 0x00); nic_write(NIC_REG_MAR6, 0x00); nic_write(NIC_REG_MAR7, 0x00); //Initialise the current pointer (to the same addr as the rx buffer start) nic_write(NIC_REG_CURR, NIC_RX_START_LOC_IN_RING); //Initialize the interface //Set page 0 nic_write(NIC_REG_CR, 0x21); //Wait 1.6mS for any tx/rx to complete nic_delay_ms(2); //Normal operation, initialize remote dma, fifo threshhold 8 bytes nic_write(NIC_REG_DCR, 0xd8); //Remote dma byte count = 0000h nic_write(NIC_REG_RBCR0, 0x00); nic_write(NIC_REG_RBCR1, 0x00); //Remote dma start address = 4000h nic_write(NIC_REG_RSAR0, 0x00); nic_write(NIC_REG_RSAR1, NIC_TX_START_LOC_IN_RING); //Monitor mode nic_write(NIC_REG_RCR, 0x20); //Place NIC in loopback nic_write(NIC_REG_TCR, 0x02); //Clear all interrupt flags nic_write(NIC_REG_ISR, 0xff); //Unmask all interrupts nic_write(NIC_REG_IMR, 0xff); //4000h < tx buffer nic_write(NIC_REG_TPSR, NIC_TX_START_LOC_IN_RING); //Stop nic, change to register page 1 nic_write(NIC_REG_CR, 0x61); //Next place to rx a packet nic_write(NIC_REG_CURR, NIC_RX_START_LOC_IN_RING); //Start nic, abort remote dma (page 0) nic_write(NIC_REG_CR, 0x22); //Change from loopback mode to normal op nic_write(NIC_REG_TCR, 0x00); //Accept broadcast packets nic_write(NIC_REG_RCR, 0x04); //Clear any pending interrupts nic_write(NIC_REG_ISR, 0xff); //Put in start mode //Start nic and set page 1 nic_write(NIC_REG_CR, 0x22); //Initialise the Transmit Configuration register nic_write(NIC_REG_TCR, 0x00); //Normal tx, CRC appended by transmitter, remote tx disable command disabled (also set in the receive overlflow routine) //Accept broadcast packets nic_write(NIC_REG_RCR, 0x04); //Accept broadcast but not multicast, packets with receive errors are rejected //----- DO FINAL FLAGS SETUP ----- nic_is_linked = 0; nic_speed_is_100mbps = 0; nic_rx_packet_waiting_to_be_dumped = 0; }
//************************************************************* //************************************************************* //********** NIC RECEIVE OVERFLOW - CLEAR RX BUFFERS ********** //************************************************************* //************************************************************* //Do special process to get all received packets from the rx ring and then reset the nic void nic_rx_overflow_clear (void) { BYTE b_temp; BYTE resend_flag; BYTE current_register; BYTE boundary_register; BYTE received_packet_status; nic_rx_packet_waiting_to_be_dumped = 0; //Read and store the value of the TXP bit in the command register (CR) b_temp = nic_read(NIC_REG_CR); //TXP is bit 2 //Issue the stop command nic_write(NIC_REG_CR, 0x21); //Wait 1.6mS for any tx or rx to complete nic_delay_ms(2); //Clear the remote byte registers nic_write(NIC_REG_RBCR0, 0x00); nic_write(NIC_REG_RBCR1, 0x00); //Read the value of the TXP bit if ((b_temp & 0x04) == 0) { //TXP is 0 - set the 'resend' variable to 0 resend_flag = 0; } else { //TXP is 1 - read the Interrupt Status Register (ISR) b_temp = nic_read(NIC_REG_ISR); if ((b_temp & 0x02) || (b_temp & 0x08)) //PTX = 1 or TXE = 1? { //One of the flags is 1 - set the 'resend' variable to 0 resend_flag = 0; } else { //Neither is 1, set the 'resend' variable to 1 resend_flag = 1; } } //Set mode 1 loopback nic_write(NIC_REG_TCR, 0x02); //Issue start command to allow remote DMA nic_write(NIC_REG_CR, 0x22); //----- REMOVE PENDING PACKETS FROM THE RECEIVE BUFFER RING ----- //Read the 'current' register (front of ring / write pointer) nic_write(NIC_REG_CR, 0x62); //Set page 1 and abort DMA current_register = nic_read(NIC_REG_CURR); //Read the 'boundary' register (back of the receive ring / read pointer) nic_write(NIC_REG_CR, 0x22); //Set page 0 and abort DMA boundary_register = nic_read(NIC_REG_BNDRY); //Check difference between current and boundary - if different then there is at least 1 packet to process while (current_register != boundary_register) { //Setup the data pointer register to read the rx packet nic_setup_read_data(); nic_rx_bytes_remaining = 4; //(Required to avoid nic_read_next_byte returning 0) //----- GET THE PRE PACKET HEADER ----- //GET THE STATUS BYTE [byte 0] nic_read_next_byte(&received_packet_status); //GET THE NEXT PACKET POINTER VALUE [byte 1] //Store ready to be used when this packet is dumped nic_read_next_byte(&nic_rx_next_packet_pointer_value); //GET THE PACKET LENGTH [bytes 2 & 3] nic_read_next_byte(&b_temp); nic_read_next_byte(&b_temp); nic_rx_dump_packet(); //Read the 'current' register (front of ring / write pointer) nic_write(NIC_REG_CR, 0x62); //Set page 1 and abort DMA current_register = nic_read(NIC_REG_CURR); //Read the 'boundary' register (back of the receive ring / read pointer) nic_write(NIC_REG_CR, 0x22); //Set page 0 and abort DMA boundary_register = nic_read(NIC_REG_BNDRY); } //----- CLEAR THE OVERFLOW WARNING BIT IN THE INTERRUPT STATUS REGISTER ----- nic_write(NIC_REG_ISR, 0xff); //----- CANCEL LOOPBACK MODE AND SET TRANSMIT BACK TO NORMAL ----- nic_write(NIC_REG_TCR, 0x00); //(TX CRC enabled) //----- IF THE 'RESEND' VARIABLE IS SET TO 1 THEN RE-ISSUE THE TRANSMIT COMMAND ----- if (resend_flag) { nic_write(NIC_REG_CR, 0x26); } }
//*************************************** //*************************************** //********** READ PHY REGISTER ********** //*************************************** //*************************************** //(Via the MII serial interface) WORD nic_read_phy_register (BYTE address) { BYTE b_count; WORD w_count; WORD data; //Set nic bank 3 nic_write(NIC_REG_BANK, 0x3303); //Write 32 1's to synchronise the interface for (b_count = 0; b_count < 32; b_count++) { nic_write(NIC_REG_MGMT, 0x3339); nic_write(NIC_REG_MGMT, 0x333d); } //Write start bits <01> nic_write_phy_0(); nic_write_phy_1(); //Read Command bits <Write = 10> nic_write_phy_1(); nic_write_phy_0(); //PHY Address, which is 00000 for LAN91C111's internal PHY nic_write_phy_0(); nic_write_phy_0(); nic_write_phy_0(); nic_write_phy_0(); nic_write_phy_0(); //PHY Reg to read - 5 bits - MSB first <Control = 00000> for (b_count = 0x10; b_count > 0; b_count >>= 1) { if (address & b_count) nic_write_phy_1(); else nic_write_phy_0(); } //Turnaround bit <Z> nic_write_phy_z(); //Get data bits (MSB first) data = 0; //Data bits (MSB first) for (w_count = 0x8000; w_count > 0; w_count >>= 1) { nic_write(NIC_REG_MGMT, 0x3330); nic_write(NIC_REG_MGMT, 0x3334); if (nic_read(NIC_REG_MGMT) & 0x02) data |= w_count; nic_write(NIC_REG_MGMT, 0x3330); } //Turnaround bit <Z> nic_write_phy_z(); return(data); }
//************************************ //************************************ //********** INITIALISE NIC ********** //************************************ //************************************ //Call with: //0 = allow speed 10 / 100 Mbps //1 = force speed to 10 Mbps void nic_initialise (BYTE init_config) { WORD data; //----------------------------- //----- DO HARDWARE RESET ----- //----------------------------- //POWER UP - WAIT 50MS nic_delay_ms(50); //RESET THE NIC nic_reset(); //WAIT 50MS nic_delay_ms(50); //------------------------------------------------- //----- WRITE THE NIC CONFIGURATION REGISTERS ----- //------------------------------------------------- //(The eeprom is not present so the nic defaults to base address 0x0300) //----- SEND MMU RESET COMMAND ----- //Set nic bank 2 nic_write(NIC_REG_BANK, 0x3302); //MMU Command //(Reset MMU to initial state) nic_write(NIC_REG_MMU_COMMAND, 0x0040); //Wait for the busy flag to clear while (nic_read(NIC_REG_MMU_COMMAND) & 0x0001) ; //----- DO BANK 0 REGISTERS ----- //Set bank 0 nic_write(NIC_REG_BANK, 0x3300); //Transmit Control (done at end) //nic_write(NIC_REG_TCR, 0x0000); //EPH Status //nic_write(NIC_REG_EPH_STATUS, 0x0000); //Receive Control (done at end) //nic_write(NIC_REG_RCR, 0x0000); //Counter //nic_write(NIC_REG_COUNTER, 0x0000); //Memory Information //nic_write(NIC_REG_MIR, 0x0000); //Receive / Phy Control Register //(Speed and duplex auto negotiation on, LEDA function, LED B function) nic_write(NIC_REG_RPCR, NIC_CONST_PPCR_REGISTER); //Reserved //nic_write(NIC_REG_RESERVED, 0x0000); //----- DO BANK 1 REGISTERS ----- //Set Bank 1 nic_write(NIC_REG_BANK, 0x3301); //Configuration //(No wait states on ARDY except for data reg if not ready, external MII disabled) nic_write(NIC_REG_CONFIG, 0xb0b1); //Base Address //nic_write(NIC_REG_BASE, 0x0000); //Individual Address (MAC) 0-1 (Bit 0 is first bit of address on the cable) nic_write(NIC_REG_IA0_1, (((WORD)our_mac_address.v[1] << 8) + (WORD)our_mac_address.v[0])); //(Litle endian) //Individual Address (MAC) 2-3 nic_write(NIC_REG_IA2_3, (((WORD)our_mac_address.v[3] << 8) + (WORD)our_mac_address.v[2])); //(Litle endian) //Individual Address (MAC) 4-5 nic_write(NIC_REG_IA4_5, (((WORD)our_mac_address.v[5] << 8) + (WORD)our_mac_address.v[4])); //(Litle endian) //General Purpose //nic_write(NIC_REG_GEN_PURPOSE, 0x0000); //Control //(Bad CRC packets are dumped, Auto release TX memory after good TX, Link Irq on, counter roll over irq off, tx error irq off) nic_write(NIC_REG_CONTROL, 0x1a90); //----- DO BANK 2 REGISTERS ----- //Set bank 2 nic_write(NIC_REG_BANK, 0x3302); //MMU Command //(Reset MMU to initial state - already done above) //nic_write(NIC_REG_MMU_COMMAND, 0x0040); //Wait for the busy flag to clear //while (nic_read(NIC_REG_MMU_COMMAND) & 0x0001) // ; //Packet Number //nic_write(NIC_REG_PNR, 0x0000); //(Litle endian) //Fifo ports //nic_write(NIC_REG_FIFO_PORTS, 0x0000); //Pointer //nic_write(NIC_REG_POINTER, 0x0000); //Data //nic_write(NIC_REG_DATA, 0x0000); //Data High //nic_write(NIC_REG_DATA_H, 0x0000); //Interrupt Status //nic_write(NIC_REG_INTERRUPT, 0x001f); //(Litle endian) //----- DO BANK 3 REGISTERS ----- //Select bank 3 nic_write(NIC_REG_BANK, 0x3303); //Multicast 0-1 nic_write(NIC_REG_MT0_1, 0x0000); //Multicast 2-3 nic_write(NIC_REG_MT2_3, 0x0000); //Multicast 4-5 nic_write(NIC_REG_MT4_5, 0x0000); //Multicast 6-7 nic_write(NIC_REG_MT6_7, 0x0000); //Management //nic_write(NIC_REG_MGMT, 0x0000); //Revision //nic_write(NIC_REG_REVISION, 0x0000); //Early Receive //(Receive IRQ Threshold = max) nic_write(NIC_REG_ERCV, 0x001f); //---------------------------------------------- //----- WRITE TO THE PHY CONTROL REGISTERS ----- //---------------------------------------------- //----- SET 'AUTO NEGOTIATE AVAILABLE SPEEDS AND DUPLEX MODES' ----- //WE USE HALF DUPLEX MODE if (init_config) { //Only 10Mbps available data = 0x0021; } else { //10/100Mbps available data = 0x00a1; } nic_write_phy_register(NIC_PHY_AUTO_NEG_ADVERTISEMENT, data); //----- TURN OFF ISOLATION MODE SO AUTO NEGOTIATION STARTS ----- nic_write_phy_register(NIC_PHY_CONTROL, 0x1000); //---------------------------- //----- ENABLE TX AND RX ----- //---------------------------- //Set bank 0 nic_write(NIC_REG_BANK, 0x3300); //Transmit Control nic_write(NIC_REG_TCR, NIC_CONST_TX_CTRL_REGISTER); //Receive Control nic_write(NIC_REG_RCR, NIC_CONST_RX_CTRL_REGISTER); //Select nic bank 2 nic_write(NIC_REG_BANK, 0x3302); //Interrupt Status //(Clear the TX INT bit if set) nic_write(NIC_REG_INTERRUPT, (NIC_CONST_IRQ_REGISTER | 0x0002)); //(little endian) nic_is_linked = 0; nic_speed_is_100mbps = 0; nic_rx_packet_waiting_to_be_dumped = 0; }
//******************************************** //******************************************** //********** CHECK FOR NIC ACTIVITY ********** //******************************************** //******************************************** //Returns 0 if no rx waiting (other nic activities may have been processed) or the number of bytes in the packet if rx is waiting WORD nic_check_for_rx (void) { WORD data; BYTE b_data; //IF NIC ISN'T FLAGGING AN INTERRUPT THEN EXIT if (!NIC_INTR0_IRQ) return(0); //Set nic bank 2 nic_write(NIC_REG_BANK, 0x3302); //Read the interrupt register data = nic_read(NIC_REG_INTERRUPT); if (data & 0x0002) //(little endian) { //------------------------------------------- //----- PACKET TX COMPLETE IRQ (TX INT) ----- //------------------------------------------- //We have Auto Release set so there is a packet that couldn't be sent due to an error and TXEN has been disabled //We will just dump the packet (we could try re-sending if we wanted to) //Read the TX FIFO packet number from the FIFO ports register data = nic_read(NIC_REG_FIFO_PORTS); //if (data & 0x0080) //Check FIFO isn't empty // //error! //Write the packet number into the packet number register nic_write(NIC_REG_PNR, (data &= 0x00ff)); //The status word can now be read if its wanted //nic_write(NIC_REG_POINTER, 0xa000); //RCV & READ bits set (no auto increment - special hardware problems fix mode) //data = nic_read(NIC_REG_DATA); //Ensure MMU isn't busy while (nic_read(NIC_REG_MMU_COMMAND) & 0x0001) ; //Send the 'Release Specific Packet' MMU Command nic_write(NIC_REG_MMU_COMMAND, 0x00a0); //Wait for the busy flag to clear while (nic_read(NIC_REG_MMU_COMMAND) & 0x0001) ; //Remove the packet number from the completion FIFO by writing the TX INT Acknowledge Register //(Clear the TX INT bit if set) nic_write(NIC_REG_INTERRUPT, (NIC_CONST_IRQ_REGISTER | 0x0002)); //(little endian) //Enable tx (TX ENA will have been cleared due to the error) //Select nic bank 0 nic_write(NIC_REG_BANK, 0x3300); //Transmit Control nic_write(NIC_REG_TCR, NIC_CONST_TX_CTRL_REGISTER); //Exit return(0); } else if (data & 0x0010) //(little endian) { //------------------------------------------ //----- RECEIVE OVERFLOW IRQ (RX_OVRN) ----- //------------------------------------------ nic_rx_overflow_clear(); return(0); } else if (data & 0x0001) //(little endian) { //------------------------------------------- //----- A PACKET RECEIVED IRQ (RCV INT) ----- //------------------------------------------- //----- READ THE RX FIFO ----- //Set nic bank 2 nic_write(NIC_REG_BANK, 0x3302); //Get the Fifo Register data = nic_read(NIC_REG_FIFO_PORTS); //Exit if there is not an rx packet waiting? //(REMPTY bit 15 = 1) if (data & 0x8000) return(0); //----- THERE IS A RX PACKET WAITING ----- //Setup the data pointer register to read the rx packet nic_setup_read_data(); nic_rx_bytes_remaining = 4; //(Required to avoid nic_read_next_byte returning 0) //----- GET THE RX STATUS AND BYTE COUNT ----- //Read the data register to get the packet nic_read_next_byte(&b_data); data = (WORD)(b_data & 0x7f); nic_read_next_byte(&b_data); data += (((WORD)(b_data & 0xfc)) << 8); //CHECK RX STATUS WORD ERROR if ( (data & 0x8000) //Check for frame alignment error //|| (data & 0x4000) //Check for broadcast (allowed) || (data & 0x2000) //Check for bad CRC //|| (data & 0x1000) //Odd number of bytes? (allowed) || (data & 0x0800) //Check for frame too long (>802.3 max size) || (data & 0x0400) //Check for frame too short (<802.3 min size) //|| (data & 0x0001) //Check for multicast packet (allowed) ) { //REJECT PACKET nic_rx_dump_packet(); return(0); } //Get the low bit of the receive byte count from the status word if (data & 0x1000) data = 1; else data = 0; //Get the byte count nic_read_next_byte(&b_data); data += (WORD)b_data; nic_read_next_byte(&b_data); data += ((WORD)(b_data & 0x07) << 8); //Sutract the status word, byte count word and control word bytes (CRC_STRIP is on so CRC is not included) nic_rx_bytes_remaining = (data - 6); nic_rx_packet_total_ethernet_bytes = nic_rx_bytes_remaining; //The ethernet stack processing routine will continue receiving the rest of the packet nic_rx_packet_waiting_to_be_dumped = PROCESS_NIC_CALLS_BEFORE_DUMP_RX; return(nic_rx_bytes_remaining); } else if (data & 0x0020) //(little endian) { //--------------------------------- //----- EPH IRQ (LINK CHANGE) ----- //--------------------------------- //----- CLEAR LE ENABLE BIT TO ACKNOWLEDGE THE IRQ ----- //Set bank 1 nic_write(NIC_REG_BANK, 0x3301); //Read control reg data = nic_read(NIC_REG_CONTROL); //Write control reg nic_write(NIC_REG_CONTROL, (data & ~0x0080)); //Write control reg nic_write(NIC_REG_CONTROL, (data | 0x0080)); //----- GET THE LINK PIN STATUS ----- //Set bank 0 nic_write(NIC_REG_BANK, 0x3300); //Get the EPH Status register data = nic_read(NIC_REG_EPH_STATUS); if (data & 0x4000) { //----- NIC IS LINKED ----- if (nic_is_linked == 0) { //----- NIC HAS JUST LINKED ----- //Read the link status if (nic_read_link_setup() & 0x01) nic_speed_is_100mbps = 1; else nic_speed_is_100mbps = 0; nic_is_linked = 1; } } else { //----- NIC IS NOT LINKED ----- if (nic_is_linked) { //----- NIC HAS JUST LOST LINK ----- //Reset the nic ready for the next link nic_initialise(NIC_INIT_SPEED); } } return(0); } //<<<<<<< ADD OTHER IRQ PIN HANDLERS HERE else { return(0); } }
void initRTL8019(void) { unsigned char i, rb; volatile unsigned char *base = (unsigned char *)0x8300; RTL8019setupPorts(); /*#define nic_write writeRTL #define nic_read readRTL*/ /* * Disable NIC interrupts. */ cbi(EIMSK, INT5); /* if(NicReset(base)) return -1;*/ #if 0 /* * Mask all interrupts and clear any interrupt status flag to set the * INT pin back to low. */ nic_write(NIC_PG0_IMR, 0); nic_write(NIC_PG0_ISR, 0xff); /* * During reset the nic loaded its initial configuration from an * external eeprom. On the ethernut board we do not have any * configuration eeprom, but simply tied the eeprom data line to * high level. So we have to clear some bits in the configuration * register. Switch to register page 3. */ nic_write(NIC_CR, NIC_CR_STP | NIC_CR_RD2 | NIC_CR_PS0 | NIC_CR_PS1); /* * The nic configuration registers are write protected unless both * EEM bits are set to 1. */ nic_write(NIC_PG3_EECR, NIC_EECR_EEM0 | NIC_EECR_EEM1); /* * Disable sleep and power down. */ nic_write(NIC_PG3_CONFIG3, 0); /* * Network media had been set to 10Base2 by the virtual EEPROM and * will be set now to auto detect. This will initiate a link test. * We don't force 10BaseT, because this would disable the link test. */ nic_write(NIC_PG3_CONFIG2, NIC_CONFIG2_BSELB); /* * Reenable write protection of the nic configuration registers * and wait for link test to complete. */ nic_write(NIC_PG3_EECR, 0); /* NutSleep(WAIT500);*/ Delay_10ms(50); /* * Switch to register page 0 and set data configuration register * to byte-wide DMA transfers, normal operation (no loopback), * send command not executed and 8 byte fifo threshold. */ nic_write(NIC_CR, NIC_CR_STP | NIC_CR_RD2); nic_write(NIC_PG0_DCR, NIC_DCR_LS | NIC_DCR_FT1); /* * Clear remote dma byte count register. */ nic_write(NIC_PG0_RBCR0, 0); nic_write(NIC_PG0_RBCR1, 0); /* * Temporarily set receiver to monitor mode and transmitter to * internal loopback mode. Incoming packets will not be stored * in the nic ring buffer and no data will be send to the network. */ nic_write(NIC_PG0_RCR, NIC_RCR_MON); nic_write(NIC_PG0_TCR, NIC_TCR_LB0); /* * Configure the nic's ring buffer page layout. * NIC_PG0_BNRY: Last page read. * NIC_PG0_PSTART: First page of receiver buffer. * NIC_PG0_PSTOP: Last page of receiver buffer. */ nic_write(NIC_PG0_TPSR, NIC_FIRST_TX_PAGE); nic_write(NIC_PG0_BNRY, NIC_STOP_PAGE - 1); nic_write(NIC_PG0_PSTART, NIC_FIRST_RX_PAGE); nic_write(NIC_PG0_PSTOP, NIC_STOP_PAGE); /* * Once again clear interrupt status register. */ nic_write(NIC_PG0_ISR, 0xff); /* * Switch to register page 1 and copy our MAC address into the nic. * We are still in stop mode. */ nic_write(NIC_CR, NIC_CR_STP | NIC_CR_RD2 | NIC_CR_PS0); for(i = 0; i < 6; i++) nic_write(NIC_PG1_PAR0 + i, mac[i]); /* * Clear multicast filter bits to disable all packets. */ for(i = 0; i < 8; i++) nic_write(NIC_PG1_MAR0 + i, 0); /* * Set current page pointer to one page after the boundary pointer. */ nic_write(NIC_PG1_CURR, NIC_START_PAGE + TX_PAGES); /* * Switch back to register page 0, remaining in stop mode. */ nic_write(NIC_CR, NIC_CR_STP | NIC_CR_RD2); /* * Take receiver out of monitor mode and enable it for accepting * broadcasts. */ nic_write(NIC_PG0_RCR, NIC_RCR_AB); /* * Clear all interrupt status flags and enable interrupts. */ nic_write(NIC_PG0_ISR, 0xff); nic_write(NIC_PG0_IMR, NIC_IMR_PRXE | NIC_IMR_PTXE | NIC_IMR_RXEE | NIC_IMR_TXEE | NIC_IMR_OVWE); /* * Fire up the nic by clearing the stop bit and setting the start bit. * To activate the local receive dma we must also take the nic out of * the local loopback mode. */ nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD2); nic_write(NIC_PG0_TCR, 0); /* NutSleep(WAIT500);*/ Delay_10ms(50); #endif /* 0 */ NicReset(); debug_print(PSTR("Init controller...")); nic_write(NIC_PG0_IMR, 0); nic_write(NIC_PG0_ISR, 0xff); nic_write(NIC_CR, NIC_CR_STP | NIC_CR_RD2 | NIC_CR_PS0 | NIC_CR_PS1); nic_write(NIC_PG3_EECR, NIC_EECR_EEM0 | NIC_EECR_EEM1); nic_write(NIC_PG3_CONFIG3, 0); nic_write(NIC_PG3_CONFIG2, NIC_CONFIG2_BSELB); nic_write(NIC_PG3_EECR, 0); /* Delay(50000);*/ Delay_10ms(200); nic_write(NIC_CR, NIC_CR_STP | NIC_CR_RD2); nic_write(NIC_PG0_DCR, NIC_DCR_LS | NIC_DCR_FT1); nic_write(NIC_PG0_RBCR0, 0); nic_write(NIC_PG0_RBCR1, 0); nic_write(NIC_PG0_RCR, NIC_RCR_MON); nic_write(NIC_PG0_TCR, NIC_TCR_LB0); nic_write(NIC_PG0_TPSR, NIC_FIRST_TX_PAGE); nic_write(NIC_PG0_BNRY, NIC_STOP_PAGE - 1); nic_write(NIC_PG0_PSTART, NIC_FIRST_RX_PAGE); nic_write(NIC_PG0_PSTOP, NIC_STOP_PAGE); nic_write(NIC_PG0_ISR, 0xff); nic_write(NIC_CR, NIC_CR_STP | NIC_CR_RD2 | NIC_CR_PS0); for(i = 0; i < 6; i++) nic_write(NIC_PG1_PAR0 + i, mac[i]); for(i = 0; i < 8; i++) nic_write(NIC_PG1_MAR0 + i, 0); nic_write(NIC_PG1_CURR, NIC_START_PAGE + TX_PAGES); nic_write(NIC_CR, NIC_CR_STP | NIC_CR_RD2); nic_write(NIC_PG0_RCR, NIC_RCR_AB); nic_write(NIC_PG0_ISR, 0xff); nic_write(NIC_PG0_IMR, 0); nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD2); nic_write(NIC_PG0_TCR, 0); /* Delay(1000000)*/ Delay_10ms(200); nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD2 | NIC_CR_PS0 | NIC_CR_PS1); rb = nic_read(NIC_PG3_CONFIG0); debug_print8(rb); switch(rb & 0xC0) { case 0x00: debug_print(PSTR("RTL8019AS ")); if(rb & 0x08) debug_print(PSTR("jumper mode: ")); if(rb & 0x20) debug_print(PSTR("AUI ")); if(rb & 0x10) debug_print(PSTR("PNP ")); break; case 0xC0: debug_print(PSTR("RTL8019 ")); if(rb & 0x08) debug_print(PSTR("jumper mode: ")); break; default: debug_print(PSTR("Unknown chip ")); debug_print8(rb); break; } if(rb & 0x04) debug_print(PSTR("BNC\x07 ")); if(rb & 0x03) debug_print(PSTR("Failed\x07 ")); /* rb = nic_read(NIC_PG3_CONFIG1); debug_print8(rb);*/ /* NutPrintFormat(0, "IRQ%u ", (rb >> 4) & 7);*/ /* debug_print("IRQ "); debug_print8((rb >> 4) & 7);*/ rb = nic_read(NIC_PG3_CONFIG2); debug_print8(rb); switch(rb & 0xC0) { case 0x00: debug_print(PSTR("Auto ")); break; case 0x40: debug_print(PSTR("10BaseT ")); break; case 0x80: debug_print(PSTR("10Base5 ")); break; case 0xC0: debug_print(PSTR("10Base2 ")); break; } return; /* HARD_RESET_RTL8019();*/ // do soft reset writeRTL( ISR, readRTL(ISR) ) ; Delay_10ms(5); writeRTL(CR,0x21); // stop the NIC, abort DMA, page 0 Delay_1ms(2); // make sure nothing is coming in or going out writeRTL(DCR, DCR_INIT); // 0x58 writeRTL(RBCR0,0x00); writeRTL(RBCR1,0x00); writeRTL(RCR,0x04); writeRTL(TPSR, TXSTART_INIT); writeRTL(TCR,0x02); writeRTL(PSTART, RXSTART_INIT); writeRTL(BNRY, RXSTART_INIT); writeRTL(PSTOP, RXSTOP_INIT); writeRTL(CR, 0x61); Delay_1ms(2); writeRTL(CURR, RXSTART_INIT); writeRTL(PAR0+0, MYMAC_0); writeRTL(PAR0+1, MYMAC_1); writeRTL(PAR0+2, MYMAC_2); writeRTL(PAR0+3, MYMAC_3); writeRTL(PAR0+4, MYMAC_4); writeRTL(PAR0+5, MYMAC_5); writeRTL(CR,0x21); writeRTL(DCR, DCR_INIT); writeRTL(CR,0x22); writeRTL(ISR,0xFF); writeRTL(IMR, IMR_INIT); writeRTL(TCR, TCR_INIT); writeRTL(CR, 0x22); // start the NIC }
//******************************************** //******************************************** //********** CHECK FOR NIC ACTIVITY ********** //******************************************** //******************************************** //Returns 0 if no rx waiting (other nic activities may have been processed) or the number of bytes in the packet if rx is waiting WORD nic_check_for_rx (void) { WORD data; BYTE b_data; BYTE current_register; BYTE received_packet_status; //-------------------------------------------------------- //----- IF NIC ISN'T FLAGGING AN INTERRUPT THEN EXIT ----- //-------------------------------------------------------- //if (NIC_INT0_IRQ == 0) // return(0); //-------------------------------------- //----- CHECK FOR RECEIVE OVERFLOW ----- //-------------------------------------- //Set nic page 0 nic_write(NIC_REG_CR, 0x20); //Read the interrupt status register if (nic_read(NIC_REG_ISR) & 0x10) { //----------------------------------- //----- RECEIVE BUFFER OVERFLOW ----- //----------------------------------- nic_rx_overflow_clear(); return(0); } //-------------------------------- //----- CHECK FOR RX WAITING ----- //-------------------------------- //Read the 'current' register (front of ring / write pointer) nic_write(NIC_REG_CR, 0x62); //Set page 1 and abort DMA current_register = nic_read(NIC_REG_CURR); //Read the 'boundary' register (back of the receive ring / read pointer) nic_write(NIC_REG_CR, 0x22); //Set page 0 and abort DMA boundary_register = nic_read(NIC_REG_BNDRY); //Check difference between current and boundary - if different then there is at least 1 packet to process if (current_register != boundary_register) { //-------------------------------------- //----- A PACKET HAS BEEN RECEIVED ----- //-------------------------------------- //Setup the data pointer register to read the rx packet nic_setup_read_data(); nic_rx_bytes_remaining = 4; //(Required to avoid nic_read_next_byte returning 0) //----- GET THE PRE PACKET HEADER ----- //GET THE STATUS BYTE [byte 0] nic_read_next_byte(&received_packet_status); //GET THE NEXT PACKET POINTER VALUE [byte 1] //Store ready to be used when this packet is dumped nic_read_next_byte(&nic_rx_next_packet_pointer_value); //GET THE PACKET LENGTH [bytes 2 & 3] nic_read_next_byte(&b_data); data = (WORD)b_data; nic_read_next_byte(&b_data); data += (((WORD)b_data) << 8); nic_rx_bytes_remaining = data - 4; nic_rx_packet_total_ethernet_bytes = nic_rx_bytes_remaining; //----- CHECK THE STATUS BYTE ----- //Check the status byte 'Received Packet Intact' flag is set to indicate packet was received without errors if ((received_packet_status & 0x01) == 0) { nic_rx_dump_packet(); return(0); } //The ethernet stack processing routine will continue receiving the rest of the packet nic_rx_packet_waiting_to_be_dumped = PROCESS_NIC_CALLS_BEFORE_DUMP_RX; return(nic_rx_bytes_remaining); } //---------------------------------- //----- CHECK IF NIC IS LINKED ----- //---------------------------------- //Set Page 3 nic_write(NIC_REG_CR, 0xe0); //Read CONFIG0. //'BNC' bit = 0 if nic is linked if ((nic_read(NIC_REG_CONFIG0) & 0x04) == 0) { //----- NIC IS LINKED ----- nic_is_linked = 1; } else { //----- NIC IS NOT LINKED ----- if (nic_is_linked) { //----- NIC HAS JUST LOST LINK ----- //Reset the nic ready for the next link nic_initialise(0); } nic_is_linked = 0; } //Set back to page 0. nic_write(NIC_REG_CR, 0x20); //<<<<<<< ADD OTHER IRQ PIN HANDLERS HERE IF IRQ'S USED return(0); }