/* * 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; }
/*! * \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; }
/*! * \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); }
/*! * \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; }
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; }
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; }
/* * 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); }
/* * 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); }
/*! * \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 }
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 }
/*! \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); } }
/*! * \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; }
/*! * \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; }
/*! * \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; }