Exemplo n.º 1
0
/*
 * Fires up the network interface. NIC interrupts
 * should have been disabled when calling this
 * function.
 *
 * \param mac Six byte unique MAC address.
 */
static int NicStart(phantom_device_t * dev, CONST uint8_t * mac)
{
    uint8_t i;

    if (NicReset(dev))
        return -1;

    /* Enable receiver. */
    nic_bs(3);
    nic_outlb(NIC_ERCV, 7);
    nic_bs(0);
    nic_outw(NIC_RCR, RCR_RXEN);

    /* Enable transmitter and padding. */
    nic_outw(NIC_TCR, TCR_PAD_EN | TCR_TXENA);

    /* Configure the PHY. */
    if (NicPhyConfig(dev))
        return -1;

    /* Set MAC address. */
    //printf("Set MAC %02X%02X%02X%02X%02X%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    nic_bs(1);
    for (i = 0; i < 6; i++)
        nic_outlb(NIC_IAR + i, mac[i]);
    //printf("OK\n");

    /* Enable interrupts. */
    nic_bs(2);
    nic_outlb(NIC_MSK, INT_ERCV | INT_RCV | INT_RX_OVRN);

    return 0;
}
Exemplo n.º 2
0
/*!
 * \brief Read contents of PHY register.
 *
 * \note NIC interrupts must have been disabled before calling this routine.
 *
 * \param reg PHY register number.
 *
 * \return Contents of the specified register.
 */
static u_int16_t NicPhyRead(phantom_device_t * dev, uint8_t reg)
{
    u_int16_t rc = 0;
    uint8_t rs;
    uint8_t i;

    /* Select register for reading. */
    rs = NicPhyRegSelect(dev, reg, 0);

    /* Switch data direction. */
    rs &= ~MGMT_MDOE;
    nic_outlb(NIC_MGMT, rs);
    nic_outlb(NIC_MGMT, rs | MGMT_MCLK);

    /* Clock data in. */
    for (i = 0; i < 16; i++) {
        nic_outlb(NIC_MGMT, rs);
        nic_outlb(NIC_MGMT, rs | MGMT_MCLK);
        rc <<= 1;
        rc |= (nic_inlb(NIC_MGMT) & MGMT_MDI) != 0;
    }

    /* This will set the clock line to low. */
    nic_outlb(NIC_MGMT, rs);

    return rc;
}
/*!
 * \brief Initialize the NIC.
 *
 * \return 0 on success, -1 otherwise.
 */
int EtherInit(void)
{
    u_char i;

    /* NIC reset. */
    if (NicReset()) {
        return -1;
    }

    /* Enable receiver. */
    nic_bs(3);
    nic_outlb(NIC_ERCV, 7);
    nic_bs(0);
    nic_outw(NIC_RCR, RCR_RXEN);

    /* Enable transmitter and padding. */
    nic_outw(NIC_TCR, TCR_PAD_EN | TCR_TXENA);

    /* Configure the PHY. */
    if (NicPhyConfig()) {
        return -1;
    }

    /* Set MAC address. */
    nic_bs(1);
    for (i = 0; i < 6; i++) {
        nic_outlb(NIC_IAR + i, confnet.cdn_mac[i]);
    }
    return 0;
}
/*!
 * \brief Reset the Ethernet controller.
 *
 * \return 0 on success, -1 otherwise.
 */
int NicReset(void)
{
    /* Disable all interrupts. */
    nic_outlb(NIC_MSK, 0);

    /* MAC and PHY software reset. */
    nic_bs(0);
    nic_outw(NIC_RCR, RCR_SOFT_RST);

    /* Enable Ethernet protocol handler. */
    nic_bs(1);
    nic_outw(NIC_CR, CR_EPH_EN);

    Delay(1);

    /* Disable transmit and receive. */
    nic_bs(0);
    nic_outw(NIC_RCR, 0);
    nic_outw(NIC_TCR, 0);

    /* Enable auto release. */
    nic_bs(1);
    nic_outw(NIC_CTR, CTR_AUTO_RELEASE);

    /* Reset MMU. */
    nic_bs(2);
    nic_outlb(NIC_MMUCR, MMU_RST);
    if (NicMmuWait(1000))
        return -1;

    return 0;
}
/*!
 * \brief Read contents of PHY register.
 *
 * \param reg PHY register number.
 *
 * \return Contents of the specified register.
 */
u_short NicPhyRead(u_char reg)
{
    u_short rc = 0;
    u_char rs;
    u_char i;

    /* Select register for reading. */
    rs = NicPhyRegSelect(reg, 0);

    /* Switch data direction. */
    rs &= ~MGMT_MDOE;
    nic_outlb(NIC_MGMT, rs);
    nic_outlb(NIC_MGMT, rs | MGMT_MCLK);

    /* Clock data in. */
    for (i = 0; i < 16; i++) {
        nic_outlb(NIC_MGMT, rs);
        nic_outlb(NIC_MGMT, rs | MGMT_MCLK);
        rc <<= 1;
        rc |= (nic_inlb(NIC_MGMT) & MGMT_MDI) != 0;
    }

    /* This will set the clock line to low. */
    nic_outlb(NIC_MGMT, rs);

    return rc;
}
Exemplo n.º 6
0
/*!
 * \brief Write value to PHY register.
 *
 * \note NIC interrupts must have been disabled before calling this routine.
 *
 * \param reg PHY register number.
 * \param val Value to write.
 */
static void NicPhyWrite(phantom_device_t * dev, uint8_t reg, u_int16_t val)
{
    u_int16_t msk;
    uint8_t rs;

    /* Select register for writing. */
    rs = NicPhyRegSelect(dev, reg, 1);

    /* Switch data direction dummy. */
    nic_outlb(NIC_MGMT, rs | MGMT_MDO);
    nic_outlb(NIC_MGMT, rs | MGMT_MDO | MGMT_MCLK);
    nic_outlb(NIC_MGMT, rs);
    nic_outlb(NIC_MGMT, rs | MGMT_MCLK);

    /* Clock data out. */
    for (msk = 0x8000; msk; msk >>= 1) {
        if (val & msk) {
            nic_outlb(NIC_MGMT, rs | MGMT_MDO);
            nic_outlb(NIC_MGMT, rs | MGMT_MDO | MGMT_MCLK);
        } else {
            nic_outlb(NIC_MGMT, rs);
            nic_outlb(NIC_MGMT, rs | MGMT_MCLK);
        }
    }

    /* Set clock line low and output line int z-state. */
    nic_outlb(NIC_MGMT, rs & ~MGMT_MDOE);
}
/*!
 * \brief Write value to PHY register.
 *
 * \param reg PHY register number.
 * \param val Value to write.
 */
void NicPhyWrite(u_char reg, u_short val)
{
    u_short msk;
    u_char rs;

    /* Select register for writing. */
    rs = NicPhyRegSelect(reg, 1);

    /* Switch data direction dummy. */
    nic_outlb(NIC_MGMT, rs | MGMT_MDO);
    nic_outlb(NIC_MGMT, rs | MGMT_MDO | MGMT_MCLK);
    nic_outlb(NIC_MGMT, rs);
    nic_outlb(NIC_MGMT, rs | MGMT_MCLK);

    /* Clock data out. */
    for (msk = 0x8000; msk; msk >>= 1) {
        if (val & msk) {
            nic_outlb(NIC_MGMT, rs | MGMT_MDO);
            nic_outlb(NIC_MGMT, rs | MGMT_MDO | MGMT_MCLK);
        } else {
            nic_outlb(NIC_MGMT, rs);
            nic_outlb(NIC_MGMT, rs | MGMT_MCLK);
        }
    }

    /* Set clock line low and output line int z-state. */
    nic_outlb(NIC_MGMT, rs & ~MGMT_MDOE);
}
Exemplo n.º 8
0
/*!
 * \brief Reset the Ethernet controller.
 *
 * \return 0 on success, -1 otherwise.
 */
static int NicReset(phantom_device_t * dev)
{
#ifdef LANC111_RESET_BIT
    sbi(LANC111_RESET_DDR, LANC111_RESET_BIT);
    sbi(LANC111_RESET_PORT, LANC111_RESET_BIT);
    NutDelay(WAIT100);
    cbi(LANC111_RESET_PORT, LANC111_RESET_BIT);
    NutDelay(WAIT250);
    NutDelay(WAIT250);
#endif

    /* Disable all interrupts. */
    nic_outlb(NIC_MSK, 0);

    /* MAC and PHY software reset. */
    nic_bs(0);
    nic_outw(NIC_RCR, RCR_SOFT_RST);

    /* Enable Ethernet protocol handler. */
    nic_bs(1);
    nic_outw(NIC_CR, CR_EPH_EN);

    NutDelay(10);

    /* Disable transmit and receive. */
    nic_bs(0);
    nic_outw(NIC_RCR, 0);
    nic_outw(NIC_TCR, 0);

    /* Enable auto release. */
    nic_bs(1);
    nic_outw(NIC_CTR, CTR_AUTO_RELEASE);

    /* Reset MMU. */
    nic_bs(2);
    nic_outlb(NIC_MMUCR, MMU_RST);
    if (NicMmuWait(dev,1000))
        return -1;

    return 0;
}
Exemplo n.º 9
0
void RealtekLoop(void)
{
    printf_P(presskey_P);
    for (;;) {
        nic_outlb(NIC_CR, NIC_CR_STP | NIC_CR_RD2);
        printf("\rid=0x%04X", nic_inw(NIC_PG0_RBCR0));
        if (GetChar()) {
            puts("");
            return;
        }
    }
}
/*!
 * \brief Receive an Ethernet frame.
 *
 * \param tms  Return with timeout after the specified
 *             number of waiting loops. On a 14 Mhz ATmega
 *             this value represents approximately the number
 *             of milliseconds to wait.
 *
 * \return The number of bytes received, 0 on timeout 
 *         or -1 in case of a failure.
 */
int EtherInput(u_short type, u_short tms)
{
    register u_short fsw;
    register u_char *buf;
    u_short fbc;

    /* Check the fifo empty bit. If it is set, then there is 
       nothing in the receiver fifo. */
    nic_bs(2);
    while (tms--) {
        if ((nic_inw(NIC_FIFO) & 0x8000) == 0) {
            break;
        }
        MicroDelay(1000);
    }
    if (nic_inw(NIC_FIFO) & 0x8000) {
        return 0;
    }

    /* Inialize pointer register. */
    nic_outw(NIC_PTR, PTR_READ | PTR_RCV | PTR_AUTO_INCR);
    MicroDelay(1);

    /* Read status word and byte count. */
    fsw = nic_inw(NIC_DATA);
    fbc = nic_inw(NIC_DATA) - 3;

    /* Check for frame errors. */
    if ((fsw & 0xAC00) == 0) {
        DEBUG("\nRx(");
        DEBUGUSHORT(fbc);
        DEBUG(")");
        if(fbc > sizeof(rframe)) {
            fbc = sizeof(rframe);
        }
        /* Perform the read. */
        buf = (u_char *) & rframe;
        fsw = fbc;
        while (fsw--) {
            *buf++ = nic_inlb(NIC_DATA);
        }
    }
    else {
        fbc = -1;
    }

    /* Release the packet. */
    nic_outlb(NIC_MMUCR, MMU_TOP);

    return fbc;
}
Exemplo n.º 11
0
static int RealtekProbe(size_t addr)
{
    uint8_t bv;

    nic_base = (uint8_t *)addr;
    bv = nic_inlb(NIC_CR);
    if(bv & (NIC_CR_PS0 | NIC_CR_PS1)) {
        nic_outlb(NIC_CR, NIC_CR_STP | NIC_CR_RD2);
    }
    if(nic_inw(NIC_PG0_RBCR0) != 0x7050) {
        return -1;
    }
    return 0;
}
Exemplo n.º 12
0
/*
 * Write data block to the NIC.
 */
static void NicWrite(phantom_device_t * dev, uint8_t * buf, u_int16_t len)
{
    register u_int16_t l = len - 1;
    register uint8_t ih = (u_int16_t) l >> 8;
    register uint8_t il = (uint8_t) l;

    if (!len)
        return;

    do {
        do {
            nic_outlb(NIC_DATA, *buf++);
        } while (il-- != 0);
    } while (ih-- != 0);
}
Exemplo n.º 13
0
/*
 * NIC interrupt entry.
 */
static void NicInterrupt(void *arg)
{
    phantom_device_t * dev = arg;

    uint8_t isr;
    uint8_t imr;
    lanc111_nic_t *ni = (lanc111_nic_t *) ((NUTDEVICE *) arg)->dev_dcb;


    ni->ni_interrupts++;

    /* Read the interrupt mask and disable all interrupts. */
    nic_bs(2);
    imr = nic_inlb(NIC_MSK);
    nic_outlb(NIC_MSK, 0);

    /* Read the interrupt status and acknowledge all interrupts. */
    isr = nic_inlb(NIC_IST);
    //printf("\n!%02X-%02X ", isr, imr);
    isr &= imr;

    /*
     * If this is a transmit interrupt, then a packet has been sent. 
     * So we can clear the transmitter busy flag and wake up the 
     * transmitter thread.
     */
    if (isr & INT_TX_EMPTY) {
        nic_outlb(NIC_ACK, INT_TX_EMPTY);
        imr &= ~INT_TX_EMPTY;
    }
    /* Transmit error. */
    else if (isr & INT_TX) {
        /* re-enable transmit */
        nic_bs(0);
        nic_outw(NIC_TCR, nic_inlb(NIC_TCR) | TCR_TXENA);
        nic_bs(2);
        nic_outlb(NIC_ACK, INT_TX);
        /* kill the packet */
        nic_outlb(NIC_MMUCR, MMU_PKT);
    }


    /*
     * If this is a receive interrupt, then wake up the receiver 
     * thread.
     */
    if (isr & INT_RX_OVRN) {
        nic_outlb(NIC_ACK, INT_RX_OVRN);
        //nic_outlb(NIC_MMUCR, MMU_TOP);
        NutEventPostFromIrq(&ni->ni_rx_rdy);
    }
    if (isr & INT_ERCV) {
        nic_outlb(NIC_ACK, INT_ERCV);
        NutEventPostFromIrq(&ni->ni_rx_rdy);
    }
    if (isr & INT_RCV) {
        nic_outlb(NIC_ACK, INT_RCV);
        imr &= ~INT_RCV;
        NutEventPostFromIrq(&ni->ni_rx_rdy);
    }

    if (isr & INT_ALLOC) {
        imr &= ~INT_ALLOC;
        NutEventPostFromIrq(&maq);
    }
    //printf(" -%02X-%02X- ", nic_inlb(NIC_IST), inb(PINE) & 0x20);
    nic_outlb(NIC_MSK, imr);
}
Exemplo n.º 14
0
/*!
 * \brief EEPROM emulator.
 *
 * Forces the chip to re-read the EEPROM contents and emulates a serial
 * EEPROM.
 *
 * If the hardware does not support this feature, then this call will
 * never return. Thus, make sure to have the driver properly configured.
 */
static void EmulateNicEeprom(void)
{
#ifdef __AVR_ENHANCED__
    register uint8_t clk;
    register uint8_t cnt;
    register uint8_t val;

    /*
     * Prepare the EEPROM emulation port bits. Configure the EEDO and
     * the EEMU lines as outputs and set EEDO to low and EEMU to high.
     */
    outb(PORTC, 0xC0);
    outb(DDRC, 0xC0);

    /*
     * Start EEPROM configuration. Stop/abort any activity and select
     * configuration page 3. Setting bit EEM0 will force the controller
     * to read the EEPROM contents.
     */

    /* Select page 3, stop and abort/complete. */
    nic_outlb(NIC_CR, NIC_CR_STP | NIC_CR_RD2 | NIC_CR_PS0 | NIC_CR_PS1);
    nic_outlb(NIC_PG3_EECR, NIC_EECR_EEM0);

    /*
     * We can avoid wasting port pins for EEPROM emulation by using the
     * upper bits of the address bus.
     */
    /*
     * No external memory access beyond this point.
     */
#if defined(__AVR_AT90CAN128__) || defined(__AVR_ATmega2561__)
    cbi(XMCRA, SRE);
#else
    cbi(MCUCR, SRE);
#endif

    /*
     * Loop for all EEPROM words.
     */
    for(cnt = 0; cnt < sizeof(nic_eeprom); ) {

        /*
         *
         * 1 start bit, always high
         * 2 op-code bits
         * 7 address bits
         * 1 dir change bit, always low
         */
        for(clk = 0; clk < 11; clk++) {
            while(bit_is_clear(RTL_EESK_PIN, RTL_EESK_BIT));
            while(bit_is_set(RTL_EESK_PIN, RTL_EESK_BIT));
        }

        /*
         * Shift out the high byte, MSB first. Our data changes at the EESK
         * rising edge. Data is sampled by the Realtek at the falling edge.
         */
        val = PRG_RDB(nic_eeprom + cnt);
        cnt++;
        for(clk = 0x80; clk; clk >>= 1) {
            while(bit_is_clear(RTL_EESK_PIN, RTL_EESK_BIT));
            if(val & clk)
                sbi(RTL_EEDO_PORT, RTL_EEDO_BIT);
            while(bit_is_set(RTL_EESK_PIN, RTL_EESK_BIT));
            cbi(RTL_EEDO_PORT, RTL_EEDO_BIT);
        }

        /*
         * Shift out the low byte.
         */
        val = PRG_RDB(nic_eeprom + cnt);
        cnt++;
        for(clk = 0x80; clk; clk >>= 1) {
            while(bit_is_clear(RTL_EESK_PIN, RTL_EESK_BIT));
            if(val & clk)
                sbi(RTL_EEDO_PORT, RTL_EEDO_BIT);
            while(bit_is_set(RTL_EESK_PIN, RTL_EESK_BIT));
            cbi(RTL_EEDO_PORT, RTL_EEDO_BIT);
        }


        /* 5 remaining clock cycles. */
        for(clk = 0; clk < 5; clk++) {
            while(bit_is_clear(RTL_EESK_PIN, RTL_EESK_BIT));
            while(bit_is_set(RTL_EESK_PIN, RTL_EESK_BIT));
        }
    }

    /*
     * Enable memory interface.
     */
#if defined(__AVR_AT90CAN128__) || defined(__AVR_ATmega2561__)
    sbi(XMCRA, SRE);
#else
    sbi(MCUCR, SRE);
#endif

    /* Reset port outputs to default. */
    outb(PORTC, 0x00);
    outb(DDRC, 0x00);
#endif
}
Exemplo n.º 15
0
static int DetectNicEeprom(void)
{
#ifdef __AVR_ENHANCED__
    register unsigned int cnt = 0;

    cli();
    /*
     * Prepare the EEPROM emulation port bits. Configure the EEDO
     * and the EEMU lines as outputs and set both lines to high.
     */
    outb(PORTC, 0xC0);
    outb(DDRC, 0xC0);

    /*
     * Force the chip to re-read the EEPROM contents.
     */
    nic_outlb(NIC_CR, NIC_CR_STP | NIC_CR_RD2 | NIC_CR_PS0 | NIC_CR_PS1);
    nic_outlb(NIC_PG3_EECR, NIC_EECR_EEM0);

    /*
     * No external memory access beyond this point.
     */
#if defined(__AVR_AT90CAN128__) || defined(__AVR_ATmega2561__)
    cbi(XMCRA, SRE);
#else
    cbi(MCUCR, SRE);
#endif

    /*
     * Check, if the chip toggles our EESK input. If not, we do not
     * have EEPROM emulation hardware.
     */
    if(bit_is_set(PINC, 5)) {
        while(++cnt && bit_is_set(PINC, 5));
    }
    else {
        while(++cnt && bit_is_clear(PINC, 5));
    }

    /*
     * Enable memory interface.
     */
#if defined(__AVR_AT90CAN128__) || defined(__AVR_ATmega2561__)
    sbi(XMCRA, SRE);
#else
    sbi(MCUCR, SRE);
#endif

    /* Reset port outputs to default. */
    outb(PORTC, 0x00);
    outb(DDRC, 0x00);

    /* Wait until controller ready. */
    while(nic_inlb(NIC_CR) != (NIC_CR_STP | NIC_CR_RD2));

    sei();
    return cnt ? 0 : -1;
#else
    return -1;
#endif
}
Exemplo n.º 16
0
/*! \fn NicRxLanc(void *arg)
 * \brief NIC receiver thread.
 *
 */
THREAD(NicRxLanc, arg)
{
    NUTDEVICE *dev;
    IFNET *ifn;
    lanc111_nic_t *ni;
    NETBUF *nb;
    uint8_t imsk;

    dev = arg;
    ifn = (IFNET *) dev->dev_icb;
    ni = (lanc111_nic_t *) dev->dev_dcb;

    /*
     * This is a temporary hack. Due to a change in initialization,
     * we may not have got a MAC address yet. Wait until a valid one
     * has been set.
     */
    while (!ETHER_IS_UNICAST(ifn->if_mac)) {
        NutSleep(10);
    }

    /*
     * Do not continue unless we managed to start the NIC. We are
     * trapped here if the Ethernet link cannot be established.
     * This happens, for example, if no Ethernet cable is plugged
     * in.
     */
    while(NicStart(ifn->if_mac)) {
        NutSleep(1000);
    }

    //LANC111_SIGNAL_MODE();

    // Enable IRQs. Enabled on irq allocation.
    //sbi(EIMSK, LANC111_SIGNAL_IRQ);

    NutEventPost(&nic->ni_tx_rdy);

    /* Run at high priority. */
    NutThreadSetPriority(9);

    for (;;) {

        /*
         * Wait for the arrival of new packets or
         * check the receiver every two second.
         */
        NutEventWait(&ni->ni_rx_rdy, 2000);

        /*
         * Fetch all packets from the NIC's internal
         * buffer and pass them to the registered handler.
         */
        imsk = nic_inlb(NIC_MSK);
        nic_outlb(NIC_MSK, 0);
        while ((nb = NicGetPacket()) != 0) {
            if (nb != (NETBUF *) 0xFFFF) {
                ni->ni_rx_packets++;
                (*ifn->if_recv) (dev, nb);
            }
        }
        nic_outlb(NIC_MSK, imsk | INT_RCV | INT_ERCV);
    }
}
Exemplo n.º 17
0
/*!
 * \brief Select specified PHY register for reading or writing.
 *
 * \note NIC interrupts must have been disabled before calling this routine.
 *
 * \param reg PHY register number.
 * \param we  Indicates type of access, 1 for write and 0 for read.
 *
 * \return Contents of the PHY interface rgister.
 */
static uint8_t NicPhyRegSelect(phantom_device_t * dev, uint8_t reg, uint8_t we)
{
    uint8_t rs;
    uint8_t msk;
    uint8_t i;

    nic_bs(3);
    rs = (nic_inlb(NIC_MGMT) & ~(MGMT_MCLK | MGMT_MDO)) | MGMT_MDOE;

    /* Send idle pattern. */
    for (i = 0; i < 33; i++) {
        nic_outlb(NIC_MGMT, rs | MGMT_MDO);
        nic_outlb(NIC_MGMT, rs | MGMT_MDO | MGMT_MCLK);
    }

    /* Send start sequence. */
    nic_outlb(NIC_MGMT, rs);
    nic_outlb(NIC_MGMT, rs | MGMT_MCLK);
    nic_outlb(NIC_MGMT, rs | MGMT_MDO);
    nic_outlb(NIC_MGMT, rs | MGMT_MDO | MGMT_MCLK);

    /* Write or read mode. */
    if (we) {
        nic_outlb(NIC_MGMT, rs);
        nic_outlb(NIC_MGMT, rs | MGMT_MCLK);
        nic_outlb(NIC_MGMT, rs | MGMT_MDO);
        nic_outlb(NIC_MGMT, rs | MGMT_MDO | MGMT_MCLK);
    } else {
        nic_outlb(NIC_MGMT, rs | MGMT_MDO);
        nic_outlb(NIC_MGMT, rs | MGMT_MDO | MGMT_MCLK);
        nic_outlb(NIC_MGMT, rs);
        nic_outlb(NIC_MGMT, rs | MGMT_MCLK);
    }

    /* Send PHY address. Zero is used for the internal PHY. */
    for (i = 0; i < 5; i++) {
        nic_outlb(NIC_MGMT, rs);
        nic_outlb(NIC_MGMT, rs | MGMT_MCLK);
    }

    /* Send PHY register number. */
    for (msk = 0x10; msk; msk >>= 1) {
        if (reg & msk) {
            nic_outlb(NIC_MGMT, rs | MGMT_MDO);
            nic_outlb(NIC_MGMT, rs | MGMT_MDO | MGMT_MCLK);
        } else {
            nic_outlb(NIC_MGMT, rs);
            nic_outlb(NIC_MGMT, rs | MGMT_MCLK);
        }
    }
    nic_outlb(NIC_MGMT, rs);

    return rs;
}
Exemplo n.º 18
0
/*!
 * \brief Load a packet into the nic's transmit ring buffer.
 *
 * Interupts must have been disabled when calling this function.
 *
 * \param nb Network buffer structure containing the packet to be sent.
 *           The structure must have been allocated by a previous
 *           call NutNetBufAlloc(). This routine will automatically
 *           release the buffer in case of an error.
 *
 * \return 0 on success, -1 in case of any errors. Errors
 *         will automatically release the network buffer 
 *         structure.
 */
static int NicPutPacket(NETBUF * nb)
{
    u_int16_t sz;
    uint8_t odd = 0;
    uint8_t imsk;

    //printf("[P]");
    /*
     * Calculate the number of bytes to be send. Do not send packets 
     * larger than the Ethernet maximum transfer unit. The MTU
     * consist of 1500 data bytes plus the 14 byte Ethernet header
     * plus 4 bytes CRC. We check the data bytes only.
     */
    if ((sz = nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz) > ETH_DATA_LEN)
        return -1;

    /* Disable all interrupts. */
    imsk = nic_inlb(NIC_MSK);
    nic_outlb(NIC_MSK, 0);

    /* Allocate packet buffer space. */
    nic_bs(2);
    nic_outlb(NIC_MMUCR, MMU_ALO);
    if (NicMmuWait(100))
        return -1;

    /* Enable interrupts including allocation success. */
    nic_outlb(NIC_MSK, imsk | INT_ALLOC);

    /* The MMU needs some time. Use it to calculate the byte count. */
    sz += nb->nb_dl.sz;
    sz += 6;
    if (sz & 1) {
        sz++;
        odd++;
    }

    /* Wait for allocation success. */
    while ((nic_inlb(NIC_IST) & INT_ALLOC) == 0) {
        if (NutEventWait(&maq, 125)) {
            nic_outlb(NIC_MMUCR, MMU_RST);
            NicMmuWait(1000);
            nic_outlb(NIC_MMUCR, MMU_ALO);
            if (NicMmuWait(100) || (nic_inlb(NIC_IST) & INT_ALLOC) == 0) {
                if (NutEventWait(&maq, 125)) {
                    return -1;
                }
            }
        }
    }

    /* Disable interrupts. */
    imsk = nic_inlb(NIC_MSK);
    nic_outlb(NIC_MSK, 0);


    nic_outlb(NIC_PNR, nic_inhb(NIC_PNR));

    nic_outw(NIC_PTR, 0x4000);

    /* Transfer control word. */
    nic_outlb(NIC_DATA, 0);
    nic_outlb(NIC_DATA, 0);

    /* Transfer the byte count. */
    nic_outw(NIC_DATA, sz);

    /* Transfer the Ethernet frame. */
    NicWrite(nb->nb_dl.vp, nb->nb_dl.sz);
    NicWrite(nb->nb_nw.vp, nb->nb_nw.sz);
    NicWrite(nb->nb_tp.vp, nb->nb_tp.sz);
    NicWrite(nb->nb_ap.vp, nb->nb_ap.sz);

    if (odd)
        nic_outlb(NIC_DATA, 0);

    /* Transfer the control word. */
    nic_outw(NIC_DATA, 0);

    /* Enqueue packet. */
    if (NicMmuWait(100))
        return -1;
    nic_outlb(NIC_MMUCR, MMU_ENQ);

    /* Enable interrupts. */
    imsk |= INT_TX | INT_TX_EMPTY;
    nic_outlb(NIC_MSK, imsk);

    return 0;
}
Exemplo n.º 19
0
/*!
 * \brief Fetch the next packet out of the receive ring buffer.
 *
 * Nic interrupts must be disabled when calling this funtion.
 *
 */
static int NicGetPacket( struct phantom_device *dev, void *buf, int len )
{
    //NETBUF *nb = 0;
    //uint8_t *buf;
    u_int16_t f_status_word;
    u_int16_t fbytecount;

    /* Check the fifo empty bit. If it is set, then there is 
       nothing in the receiver fifo. */
    nic_bs(2);
    //if (nic_inw(NIC_FIFO) & 0x8000)
    //    return 0;

    // TODO cond/sem timed wait
    while(nic_inw(NIC_FIFO) & 0x8000)
        hal_sleep_msec(100);

    /* Inialize pointer register. */
    nic_outw(NIC_PTR, PTR_READ | PTR_RCV | PTR_AUTO_INCR);
    _NOP();
    _NOP();
    _NOP();
    _NOP();

    /* Read status word and byte count. */
    f_status_word = nic_inw(NIC_DATA);
    fbytecount = nic_inw(NIC_DATA);
    //printf("[SW=%04X,BC=%04X]", f_status_word, fbytecount);


    int ret = ERR_IO_ERROR;

    /* Check for frame errors. */
    if (f_status_word & 0xAC00) {
        //nb = (NETBUF *) 0xFFFF;
        ret = ERR_IO_ERROR;
    }
    /* Check the byte count. */
    else if (fbytecount < 66 || fbytecount > 1524) {
        //nb = (NETBUF *) 0xFFFF;
        ret = ERR_IO_ERROR;
    }
    else {
        /* 
         * Allocate a NETBUF. 
         * Hack alert: Rev A chips never set the odd frame indicator.
         */
        fbytecount -= 3;

        if( len < fbytecount )
            ret = ERR_VFS_INSUFFICIENT_BUF;
        else
        {
            NicRead( dev, buf, fbytecount);
            ret = fbytecount;
        }
    }

    /* Release the packet. */
    nic_outlb(NIC_MMUCR, MMU_TOP);

    return ret;
}
/*!
 * \brief Send an Ethernet frame.
 *
 * \param dmac Destination MAC address.
 * \param type Frame type.
 * \param len  Frame size.
 *
 * \return 0 on success, -1 otherwise.
 */
int EtherOutput(const u_char * dmac, u_short type, u_short len)
{
    ETHERHDR *eh;
    u_char *cp;

    /*
     * Set the Ethernet header.
     */
    if (type == ETHERTYPE_ARP) {
        cp = (u_char *) & arpframe;
    } else {
        cp = (u_char *) & sframe;
    }
    eh = (ETHERHDR *)cp;
    memcpy_(eh->ether_shost, confnet.cdn_mac, 6);
    memcpy_(eh->ether_dhost, dmac, 6);
    eh->ether_type = type;

    /*
     * The total packet length includes 
     * - status word (2 bytes)
     * - byte count (2 bytes)
     * - destination address (6 bytes)
     * - source address (6 bytes)
     * - Ethernet type (2 bytes)
     * - data bytes (variable)
     * - control word (2 bytes)
     * Thus we add 20 to the number of data bytes. We didn't
     * manage to get an odd number of bytes transmitted, so
     * add another byte.
     */
    if((len += 20) & 1) {
        len++;
    }

    DEBUG(" Tx(");
    DEBUGUSHORT(len);
    DEBUG(")");

    /* Allocate transmit packet buffer space. */
    nic_bs(2);
    nic_outlb(NIC_MMUCR, MMU_ALO);
    if (NicMmuWait(100)) {
        return -1;
    }

    /*
     * An allocation error might appear when incoming packets occupy 
     * all the buffer. Reset the MMU to release all memory. This is
     * very drastic, but OK for our sequential boot loader.
     */
    if ((nic_inlb(NIC_IST) & INT_ALLOC) == 0) {
        DEBUG("[MMURST]");
        nic_outlb(NIC_MMUCR, MMU_RST);
        NicMmuWait(1000);
        nic_outlb(NIC_MMUCR, MMU_ALO);
        if (NicMmuWait(100) || (nic_inlb(NIC_IST) & INT_ALLOC) == 0) {
            return -1;
        }
    }

    /* 
     * Read the number of the allcocated packet from the allocation 
     * result register and write it to the packet number register.
     */
    nic_outlb(NIC_PNR, nic_inhb(NIC_PNR));

    /*
     * Initially set the pointer register address to 2 and enable
     * auto increment. The first two bytes will be used by the CSMA 
     * to store the status word upon transmit completion. 
     */
    nic_outw(NIC_PTR, PTR_AUTO_INCR | 2);

    /* 
     * Transfer the byte count and the data bytes.
     */
    nic_outw(NIC_DATA, len);
    while (len--) {
        nic_outlb(NIC_DATA, *cp);
        cp++;
    }
    
    /* 
     * Transfer the control word. As stated above, we never succeeded
     * in sending an odd number of bytes.
     */
    nic_outw(NIC_DATA, 0);

    /* Enqueue packet. */
    NicMmuWait(100);
    nic_outlb(NIC_MMUCR, MMU_ENQ);

    return 0;
}