📄 nicrtl.c
字号:
} else { while (++cnt && bit_is_clear(RTL_EESK_PIN, RTL_EESK_BIT)); }#ifdef RTL_EE_MEMBUS /* * Enable memory interface. */#ifdef __AVR_ENHANCED__ /* On the ATmega 128 we release bits 5-7 as normal port pins. */ outb(XMCRB, inb(XMCRB) & ~(_BV(XMM0) | _BV(XMM1)));#else /* On the ATmega 103 we have to disable the external memory interface. */ sbi(MCUCR, SRE);#endif#endif /* Reset port outputs to default. */ cbi(RTL_EEDO_PORT, RTL_EEDO_BIT); cbi(RTL_EEDO_DDR, RTL_EEDO_BIT);#ifdef RTL_EEMU_BIT cbi(RTL_EEMU_PORT, RTL_EEMU_BIT); cbi(RTL_EEMU_DDR, RTL_EEMU_BIT);#endif /* Restore previous interrupt enable state. */ NutExitCritical(); /* Wait until controller ready. */ while (NICINB(NIC_CR) != (NIC_CR_STP | NIC_CR_RD2)); return cnt ? 0 : -1;#else return -1;#endif}#ifdef RTL_EESK_BIT/* * Emulated EEPROM contents. * * In jumper mode our influence is quite limited, only CONFIG3 and CONFIG4 * can be modified. */static prog_char nic_eeprom[18] = { 0xFF, /* CONFIG2: jPL1 jPL0 0 jBS4 jBS3 jBS2 jBS1 jBS0 */ 0xFF, /* CONFIG1: 1 jIRQS2 jIRQS1 jIRQS0 jIOS3 jIOS2 jIOS1 jIOS0 */ 0xFF, /* CONFIG4: - - - - - - - IOMS */ 0x30, /* CONFIG3 PNP FUDUP LEDS1 LEDS0 - 0 PWRDN ACTB */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* MAC */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF /* ID */};#endif/*! * \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 RTL_EESK_BIT register u_char clk; register u_char cnt; register u_char val; /* * Disable all interrupts. This routine requires critical timing * and optionally may disable the memory interface. */ NutEnterCritical(); /* * Prepare the EEPROM emulation port bits. Configure the EEDO and * the EEMU lines as outputs and set EEDO to low and EEMU to high. */ cbi(RTL_EEDO_PORT, RTL_EEDO_BIT); sbi(RTL_EEDO_DDR, RTL_EEDO_BIT);#ifdef RTL_EEMU_BIT sbi(RTL_EEMU_PORT, RTL_EEMU_BIT); sbi(RTL_EEMU_DDR, RTL_EEMU_BIT);#endif NutDelay(20); /* * 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. */ NICOUTB(NIC_CR, NIC_CR_STP | NIC_CR_RD2 | NIC_CR_PS0 | NIC_CR_PS1); NICOUTB(NIC_PG3_EECR, NIC_EECR_EEM0); /* * We can avoid wasting port pins for EEPROM emulation by using the * upper bits of the address bus. */#ifdef RTL_EE_MEMBUS /* * No external memory access beyond this point. */#ifdef __AVR_ENHANCED__ /* On the ATmega 128 we release bits 5-7 as normal port pins. */ outb(XMCRB, inb(XMCRB) | _BV(XMM0) | _BV(XMM1));#else /* On the ATmega 103 we have to disable the external memory interface. */ cbi(MCUCR, SRE);#endif#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)); } }#ifdef RTL_EE_MEMBUS /* * Enable memory interface. */#ifdef __AVR_ENHANCED__ /* On the ATmega 128 we release bits 5-7 as normal port pins. */ outb(XMCRB, inb(XMCRB) & ~(_BV(XMM0) | _BV(XMM1)));#else /* On the ATmega 103 we have to disable the external memory interface. */ sbi(MCUCR, SRE);#endif#endif /* Reset port outputs to default. */ cbi(RTL_EEDO_DDR, RTL_EEDO_BIT);#ifdef RTL_EEMU_BIT cbi(RTL_EEMU_PORT, RTL_EEMU_BIT); cbi(RTL_EEMU_DDR, RTL_EEMU_BIT);#endif /* Restore previous interrupt enable state. */ NutExitCritical();#endif}/* * Fires up the network interface. NIC interrupts * should have been disabled when calling this * function. */static int NicStart(CONST u_char * mac){ u_char i; if (NicReset()) { return -1; } if (DetectNicEeprom() == 0) { EmulateNicEeprom(); } /* * Mask all interrupts and clear any interrupt status flag to set the * INT pin back to low. */ NICOUTB(NIC_PG0_IMR, 0); NICOUTB(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. */ NICOUTB(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. */ NICOUTB(NIC_PG3_EECR, NIC_EECR_EEM0 | NIC_EECR_EEM1); /* * 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. */ NICOUTB(NIC_PG3_CONFIG2, NIC_CONFIG2_BSELB); /* * Disable sleep and power down. * * The virtual EEPROM (resistor tight to VCC) will set all bits of * CONFIG3 to 1. Unfortunately we are not able to modify the full * duplex bit. The only solution is to use a real EEPROM or emulate * one. */ NICOUTB(NIC_PG3_CONFIG3, NIC_CONFIG3_LEDS1 | NIC_CONFIG3_LEDS1); /* * Reenable write protection of the nic configuration registers * and wait for link test to complete. */ NICOUTB(NIC_PG3_EECR, 0); NutDelay(255); /* * 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. */ NICOUTB(NIC_CR, NIC_CR_STP | NIC_CR_RD2); NICOUTB(NIC_PG0_DCR, NIC_DCR_LS | NIC_DCR_FT1); /* * Clear remote dma byte count register. */ NICOUTB(NIC_PG0_RBCR0, 0); NICOUTB(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. */ NICOUTB(NIC_PG0_RCR, NIC_RCR_MON); NICOUTB(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. */ NICOUTB(NIC_PG0_TPSR, NIC_FIRST_TX_PAGE); NICOUTB(NIC_PG0_BNRY, NIC_STOP_PAGE - 1); NICOUTB(NIC_PG0_PSTART, NIC_FIRST_RX_PAGE); NICOUTB(NIC_PG0_PSTOP, NIC_STOP_PAGE); /* * Once again clear interrupt status register. */ NICOUTB(NIC_PG0_ISR, 0xff); /* * Switch to register page 1 and copy our MAC address into the nic. * We are still in stop mode. */ NICOUTB(NIC_CR, NIC_CR_STP | NIC_CR_RD2 | NIC_CR_PS0); for (i = 0; i < 6; i++) NICOUTB(NIC_PG1_PAR0 + i, mac[i]); /* * Clear multicast filter bits to disable all packets. */ for (i = 0; i < 8; i++) NICOUTB(NIC_PG1_MAR0 + i, 0); /* * Set current page pointer to one page after the boundary pointer. */ NICOUTB(NIC_PG1_CURR, NIC_FIRST_RX_PAGE); /* * Switch back to register page 0, remaining in stop mode. */ NICOUTB(NIC_CR, NIC_CR_STP | NIC_CR_RD2); /* * Take receiver out of monitor mode and enable it for accepting * broadcasts. */ NICOUTB(NIC_PG0_RCR, NIC_RCR_AB); /* * Clear all interrupt status flags and enable interrupts. */ NICOUTB(NIC_PG0_ISR, 0xff); /* Note: transmitter if polled, thus no NIC_IMR_PTXE */ NICOUTB(NIC_PG0_IMR, NIC_IMR_PRXE | 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. */ NICOUTB(NIC_CR, NIC_CR_STA | NIC_CR_RD2); NICOUTB(NIC_PG0_TCR, 0); NutDelay(255); return 0;}/*! * Complete remote DMA. */static void NicCompleteDma(void){ u_char i; /* * Complete remote dma. */ NICOUTB(NIC_CR, NIC_CR_STA | NIC_CR_RD2); /* * Check that we have a DMA complete flag. */ for (i = 0; i <= 20; i++) if (NICINB(NIC_PG0_ISR) & NIC_ISR_RDC) break; /* * Reset remote dma complete flag. */ NICOUTB(NIC_PG0_ISR, NIC_ISR_RDC);}/* * Write data block to the NIC. */static void NicWrite(u_char * buf, u_short len){ register u_short l = len - 1; register u_char ih = (u_short) l >> 8; register u_char il = (u_char) l; if (!len) return; do { do { NICOUTB(NIC_IOPORT, *buf++); } while (il-- != 0); } while (ih-- != 0);}/* * Read data block from the NIC. */static void NicRead(u_char * buf, u_short len){ register u_short l = len - 1; register u_char ih = (u_short) l >> 8; register u_char il = (u_char) l; if (!len) return; do { do { *buf++ = NICINB(NIC_IOPORT); } while (il-- != 0); } while (ih-- != 0);}/*! * \brief Load a packet into the nic's transmit ring buffer. * * * \param base NIC hardware base address. * \param nb Network buffer structure containing the packet to be sent. * The structure must have been allocated by a previous * call NutNetBufAlloc(). * * \return 0 on success, -1 in case of any errors. Errors * will automatically release the network buffer * structure. */static int NicPutPacket(NETBUF * nb){ u_short sz; u_short i; u_char padding = 0; /* * Calculate the number of bytes to be send. Do not * send packets larger than 1514 bytes. * * The previous version was wrong by specifying a maximum * of 1518, because it didn't take the CRC into account, * which is generated by the hardware and automatically * appended. Thanks to Bengt Florin, who discovered this. */ sz = nb->nb_dl.sz + nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz; if (sz > 1514) return -1; /* * The controller will not append pad bytes, * so we have to do this. */ if (sz < 60) { padding = (u_char) (60 - sz); sz = 60; } /* * Bengt Florin introduces polling mode for the transmitter. Be * aware, that this may introduce other problems. If a high * priority thread is waiting for the transmitter, it may hold * the CPU for more than 1.2 milliseconds in worst cases. */ while (NICINB(NIC_CR) & NIC_CR_TXP) NutThreadYield(); /* we don't want to be interrupted by NIC owerflow */ cbi(EIMSK, RTL_SIGNAL_IRQ); /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -