//**************************************************************
//**************************************************************
//********** 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);
}
Esempio n. 5
0
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;
}
Esempio n. 6
0
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);
}
Esempio n. 13
0
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);
	}
}
Esempio n. 19
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);
}