📄 lanc111.c
字号:
#define PHYSOR_SPDDET 0x0080 /*!< \ref NIC_PHYSOR bit mask, 100/10 speed detected. */#define PHYSOR_DPLXDET 0x0040 /*!< \ref NIC_PHYSOR bit mask, duplex detected. *//*! * \brief PHY mask register. */#define NIC_PHYMSK 19#define PHYMSK_MINT 0x8000 /*!< \ref NIC_PHYMSK bit mask, enables \ref PHYSOR_INT interrupt. */#define PHYMSK_MLNKFAIL 0x4000 /*!< \ref NIC_PHYMSK bit mask, enables \ref PHYSOR_LNKFAIL interrupt. */#define PHYMSK_MLOSSSYN 0x2000 /*!< \ref NIC_PHYMSK bit mask, enables \ref PHYSOR_LOSSSYNC interrupt. */#define PHYMSK_MCWRD 0x1000 /*!< \ref NIC_PHYMSK bit mask, enables \ref PHYSOR_CWRD interrupt. */#define PHYMSK_MSSD 0x0800 /*!< \ref NIC_PHYMSK bit mask, enables \ref PHYSOR_SSD interrupt. */#define PHYMSK_MESD 0x0400 /*!< \ref NIC_PHYMSK bit mask, enables \ref PHYSOR_ESD interrupt. */#define PHYMSK_MRPOL 0x0200 /*!< \ref NIC_PHYMSK bit mask, enables \ref PHYSOR_RPOL interrupt. */#define PHYMSK_MJAB 0x0100 /*!< \ref NIC_PHYMSK bit mask, enables \ref PHYSOR_JAB interrupt. */#define PHYMSK_MSPDDT 0x0080 /*!< \ref NIC_PHYMSK bit mask, enables \ref PHYSOR_SPDDET interrupt. */#define PHYMSK_MDPLDT 0x0040 /*!< \ref NIC_PHYMSK bit mask, enables \ref PHYSOR_DPLXDET interrupt. */#define MSBV(bit) (1 << ((bit) - 8))#define nic_outlb(addr, val) (*(volatile u8_t *)(addr) = (val))#define nic_outhb(addr, val) (*(volatile u8_t *)((addr) + 1) = (val))#define nic_outwx(addr, val) (*(volatile u16_t *)(addr) = (val))#define nic_outw(addr, val) { \ *(volatile u8_t *)(addr) = (u8_t)(val); \ *((volatile u8_t *)(addr) + 1) = (u8_t)((val) >> 8); \}#define nic_inlb(addr) (*(volatile u8_t *)(addr))#define nic_inhb(addr) (*(volatile u8_t *)((addr) + 1))#define nic_inw(addr) (*(volatile u16_t *)(addr))#define nic_bs(bank) nic_outlb(NIC_BSR, bank)/*! * \struct _NICINFO lanc111.h dev/lanc111.h * \brief Network interface controller information structure. *//*@}*//*! * \addtogroup xgNicLanc111 *//*@{*//*! * \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 u8_t NicPhyRegSelect(u8_t reg, u8_t we){ u8_t rs; u8_t msk; u8_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 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 u16_t NicPhyRead(u8_t reg){ u16_t rc = 0; u8_t rs; u8_t 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(u8_t reg, u16_t val){ u16_t msk; u8_t 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 Configure the internal PHY. * * Reset the PHY and initiate auto-negotiation. */static int NicPhyConfig(void){ u16_t phy_sor; u16_t phy_sr; u16_t phy_to; u16_t mode; /* * Reset the PHY and wait until this self clearing bit * becomes zero. We sleep 63 ms before each poll and * give up after 3 retries. */ //printf("Reset PHY.."); NicPhyWrite(NIC_PHYCR, PHYCR_RST); for (phy_to = 0;; phy_to++) { NutSleep(63); if ((NicPhyRead(NIC_PHYCR) & PHYCR_RST) == 0) break; if (phy_to > 3) return -1; } //printf("OK\n"); /* Store PHY status output. */ phy_sor = NicPhyRead(NIC_PHYSOR); /* Enable PHY interrupts. */ NicPhyWrite(NIC_PHYMSK, PHYMSK_MLOSSSYN | PHYMSK_MCWRD | PHYMSK_MSSD | PHYMSK_MESD | PHYMSK_MRPOL | PHYMSK_MJAB | PHYMSK_MSPDDT | PHYMSK_MDPLDT); /* Set RPC register. */ mode = RPCR_ANEG | RPCR_LEDA_PAT | RPCR_LEDB_PAT; nic_bs(0); nic_outw(NIC_RPCR, mode);#ifdef NIC_FIXED /* Disable link. */ phy_sr = NicPhyRead(NIC_PHYCFR1); NicPhyWrite(NIC_PHYCFR1, phy_sr | 0x8000); NutSleep(63); /* Set fixed capabilities. */ NicPhyWrite(NIC_PHYCR, NIC_FIXED); nic_bs(0); nic_outw(NIC_RPCR, mode); /* Enable link. */ phy_sr = NicPhyRead(NIC_PHYCFR1); NicPhyWrite(NIC_PHYCFR1, phy_sr & ~0x8000); phy_sr = NicPhyRead(NIC_PHYCFR1);#else /* * Advertise our capabilities, initiate auto negotiation * and wait until this has been completed. */ //printf("Negotiate.."); NicPhyWrite(NIC_PHYANAD, PHYANAD_TX_FDX | PHYANAD_TX_HDX | PHYANAD_10FDX | PHYANAD_10_HDX | PHYANAD_CSMA); NutSleep(63); for (phy_to = 0, phy_sr = 0;; phy_to++) { /* Give up after 10 seconds. */ if (phy_to >= 1024) return -1; /* Restart auto negotiation every 4 seconds or on failures. */ if ((phy_to & 127) == 0 /* || (phy_sr & PHYSR_REM_FLT) != 0 */ ) { NicPhyWrite(NIC_PHYCR, PHYCR_ANEG_EN | PHYCR_ANEG_RST); //printf("Restart.."); NutSleep(63); } /* Check if we are done. */ phy_sr = NicPhyRead(NIC_PHYSR); //printf("[SR %04X]", phy_sr); if (phy_sr & PHYSR_ANEG_ACK) break; NutSleep(63); } //printf("OK\n");#endif return 0;}/*! * \brief Wait until MMU is ready. * * Poll the MMU command register until \ref MMUCR_BUSY * is cleared. * * \param tmo Timeout in milliseconds. * * \return 0 on success or -1 on timeout. */static INLINE int NicMmuWait(u16_t tmo){ while (tmo--) { if ((nic_inlb(NIC_MMUCR) & MMUCR_BUSY) == 0) break; NutDelay(1); } return tmo ? 0 : -1;}/*! * \brief Reset the Ethernet controller. * * \return 0 on success, -1 otherwise. */static int NicReset(void){#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(1000)) return -1; return 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(CONST u8_t * mac){ u8_t i; 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. */ //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;}/* * NIC interrupt entry. */#if 0static void NicInterrupt(void *arg){ u8_t isr; u8_t imr; NICINFO *ni = (NICINFO *) ((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; NutEventPostFromIrq(&ni->ni_tx_rdy); } /* 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); NutEventPostFromIrq(&ni->ni_tx_rdy); } /* * 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); } 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);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -