⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 at91_ether.c

📁 RT-Thread是发展中的下一代微内核嵌入式实时操作系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Ethernet driver for the Atmel AT91RM9200 * Based on NetBSD AT91 EMAC driver */#include <rthw.h>#include <rtthread.h>#include <AT9200.h>#include <mii.h>#include <ethtool.h>#include <AT91RM9200_EMAC.h>#include <pio.h>#include <at91_ether.h>#include <ethernetif.h>#define barrier() __asm__ __volatile__("": : :"memory")#define CONFIG_AT91_ETHER_RMII/* Davicom specific registers */#define MII_DSCSR_REG   17#define MII_DSINTR_REG  21AT91PS_SYS AT91_SYS = (AT91PS_SYS) AT91C_BASE_SYS;AT91PS_EMAC AT91_EMAC = (AT91PS_EMAC) AT91C_BASE_EMAC;#define MAX_ADDR_LEN 6struct net_device_stats{	unsigned long rx_packets;		/* total packets received	*/	unsigned long tx_packets;		/* total packets transmitted	*/	unsigned long rx_errors;		/* receive bad packets */	unsigned long tx_errors;		/* transmit bad packets */};#define	IFF_PROMISC		0x100		/* receive all packets		*/#define	IFF_ALLMULTI	0x200		/* receive all multicast packets*/#define PHY_IRQ			32#define MAX_RBUFF_SZ	0x600		/* 1518 rounded up */#define MAX_RX_DESCR	9			/* max number of receive buffers */struct rbf_t{	rt_uint32_t addr;	rt_uint32_t size;};struct net_device{	/* inherit from ethernet device */	struct eth_device parent;	int state ;	rt_uint32_t current_rb_index;				/* current receive buffer index */	/* interface address info. */	rt_uint8_t  dev_addr[MAX_ADDR_LEN];			/* hw address	*/	rt_uint8_t  phy_addr;	struct rbf_t 	descriptors[MAX_RX_DESCR];			/* must be on sizeof (rbf_t) boundary */	rt_uint8_t 		rx_buf[MAX_RX_DESCR][MAX_RBUFF_SZ];	/* must be on long boundary */	rt_uint8_t 		tx_buf[MAX_RBUFF_SZ];				/* must be on long boundary */	struct net_device_stats stats;};static struct net_device  at91_dev_entry;static struct net_device *at91_dev =&at91_dev_entry;/* ........................... PHY INTERFACE ........................... *//* * Write value to the a PHY register * Note: MDI interface is assumed to already have been enabled. */rt_inline void write_phy(rt_uint8_t phy_addr, rt_uint8_t address, rt_uint32_t value){	AT91_EMAC->EMAC_MAN = (AT91C_EMAC_HIGH | AT91C_EMAC_CODE_802_3 | AT91C_EMAC_RW_W					  |((phy_addr & 0x1f) << 23)| (address << 18)) + (value & 0xffff);	/* Wait until IDLE bit in Network Status register is cleared */	// TODO: Enforce some maximum loop-count?	while (!(AT91_EMAC->EMAC_SR & AT91C_EMAC_IDLE))	{		barrier();	}}/* * Read value stored in a PHY register. * Note: MDI interface is assumed to already have been enabled. */rt_inline void read_phy(rt_uint8_t phy_addr, rt_uint8_t address, rt_uint32_t *value){	AT91_EMAC->EMAC_MAN = AT91C_EMAC_HIGH | AT91C_EMAC_CODE_802_3 | AT91C_EMAC_RW_R					 |((phy_addr & 0x1f) << 23)| (address << 18);	/* Wait until IDLE bit in Network Status register is cleared */	// TODO: Enforce some maximum loop-count?	while (!(AT91_EMAC->EMAC_SR & AT91C_EMAC_IDLE))	{		barrier();	}	*value = (AT91_EMAC->EMAC_MAN & 0x0000ffff);}/* ........................... PHY MANAGEMENT .......................... *//* * Access the PHY to determine the current Link speed and Mode, and update the * MAC accordingly. * If no link or auto-negotiation is busy, then no changes are made. * Returns:  0 : OK *          -1 : No link *          -2 : AutoNegotiation still in progress */static int update_linkspeed(struct net_device *dev){	rt_uint32_t bmsr, bmcr, lpa, mac_cfg;	rt_uint32_t speed, duplex;	/* Link up, or auto-negotiation still in progress */	read_phy(dev->phy_addr ,MII_BMSR, &bmsr);	read_phy(dev->phy_addr ,MII_BMSR, &bmsr);	if (!(bmsr & BMSR_LSTATUS))		return -1;			/* no link */	read_phy(dev->phy_addr, MII_BMCR, &bmcr);	if (bmcr & BMCR_ANENABLE)	{				/* AutoNegotiation is enabled */		if (!(bmsr & BMSR_ANEGCOMPLETE)) return -2;	/* auto-negotitation in progress */		read_phy(dev->phy_addr, MII_LPA, &lpa);		if ((lpa & LPA_100FULL) || (lpa & LPA_100HALF)) speed = SPEED_100;		else speed = SPEED_10;		if ((lpa & LPA_100FULL) || (lpa & LPA_10FULL)) duplex = DUPLEX_FULL;		else duplex = DUPLEX_HALF;	}	else	{		speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10;		duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;	}	/* Update the MAC */	mac_cfg = AT91_EMAC->EMAC_CFG & ~(AT91C_EMAC_SPD | AT91C_EMAC_FD);	if (speed == SPEED_100)	{		if (duplex == DUPLEX_FULL)		/* 100 Full Duplex */			AT91_EMAC->EMAC_CFG = mac_cfg | AT91C_EMAC_SPD | AT91C_EMAC_FD;		else					/* 100 Half Duplex */			AT91_EMAC->EMAC_CFG = mac_cfg | AT91C_EMAC_SPD;	}	else	{		if (duplex == DUPLEX_FULL)		/* 10 Full Duplex */			AT91_EMAC->EMAC_CFG = mac_cfg | AT91C_EMAC_FD;		else					/* 10 Half Duplex */			AT91_EMAC->EMAC_CFG = mac_cfg;	}	return 0;}void netif_carrier_off(struct net_device *dev ){	dev->state = 0;}void netif_carrier_on(struct net_device *dev ){	dev->state = 1;}/* * Handle interrupts from the PHY */void at91ether_phy_interrupt(int irq){	int status;	rt_uint32_t phy;	AT91_EMAC->EMAC_CTL |= AT91C_EMAC_MPE;	/* enable management port */	read_phy(at91_dev->phy_addr, MII_DSINTR_REG, &phy);	/* acknowledge interrupt in PHY */	status = AT91_SYS->PIOC_ISR;		/* acknowledge interrupt in PIO */	status = update_linkspeed(at91_dev);	if (status == -1)	{		/* link is down */		netif_carrier_off(at91_dev);	}	else if (status == -2)	{		/* auto-negotiation in progress */		/* Do nothing - another interrupt generated when negotiation complete */	}	else	{		/* link is operational */		netif_carrier_on(at91_dev);	}	AT91_EMAC->EMAC_CTL &= ~AT91C_EMAC_MPE;	/* disable management port */}/* * Initialize and enable the PHY interrupt when link-state changes */void enable_phyirq(struct net_device *dev){	static int first_init = 0;	if (first_init == 0)	{		// TODO: Check error code.  Really need a generic PIO (interrupt)		// layer since we're really only interested in the PC4 line.		rt_hw_interrupt_install(PHY_IRQ, at91ether_phy_interrupt, 0);		rt_hw_interrupt_umask(PHY_IRQ);		AT91_SYS->PIOC_ODR = AT91C_PIO_PC4;	/* Configure as input */		first_init = 1;	}	else	{		rt_uint32_t dsintr, status;		status = AT91_SYS->PIOC_ISR;		/* clear any pending PIO interrupts */		AT91_SYS->PIOC_IER = AT91C_PIO_PC4;	/* Enable interrupt */		AT91_EMAC->EMAC_CTL |= AT91C_EMAC_MPE;	/* enable management port */		read_phy(dev->phy_addr, MII_DSINTR_REG, &dsintr);		dsintr = dsintr & ~0xf00;		/* clear bits 8..11 */		write_phy(dev->phy_addr,MII_DSINTR_REG, dsintr);		AT91_EMAC->EMAC_CTL &= ~AT91C_EMAC_MPE;	/* disable management port */	}}/* * Disable the PHY interrupt */void disable_phyirq(struct net_device *dev){	rt_uint32_t dsintr;	rt_base_t level;	level = rt_hw_interrupt_disable();	AT91_EMAC->EMAC_CTL |= AT91C_EMAC_MPE;	/* enable management port */	read_phy(dev->phy_addr, MII_DSINTR_REG, &dsintr);	dsintr = dsintr | 0xf00;			/* set bits 8..11 */	write_phy(dev->phy_addr, MII_DSINTR_REG, dsintr);	AT91_EMAC->EMAC_CTL &= ~AT91C_EMAC_MPE;	/* disable management port */	rt_hw_interrupt_enable(level);	AT91_SYS->PIOC_IDR = AT91C_PIO_PC4;		/* Disable interrupt */}/** * is_valid_ether_addr - Determine if the given Ethernet address is valid * @addr: Pointer to a six-byte array containing the Ethernet address * * Check that the Ethernet address (MAC) is not 00:00:00:00:00:00, is not * a multicast address, and is not FF:FF:FF:FF:FF:FF.  The multicast * and FF:FF:... tests are combined into the single test "!(addr[0]&1)". * * Return true if the address is valid. */rt_inline int is_valid_ether_addr(rt_uint8_t *addr){	const char zaddr[6] ={ 0, };	return !(addr[0]&1) && rt_memcmp( addr, zaddr, 6);}/* ......................... ADDRESS MANAGEMENT ........................ *//* * Set the ethernet MAC address in dev->dev_addr */void get_mac_address(struct net_device *dev){	static rt_uint8_t def_mac[] = {0x00,0xaa,0xbb,0xcc,0xdd,0x00};	rt_uint8_t addr[6];	rt_uint32_t hi, lo;	/* Check if bootloader set address in Specific-Address 1 */	hi = AT91_EMAC->EMAC_SA1H;	lo = AT91_EMAC->EMAC_SA1L;	addr[0] = (lo & 0xff);	addr[1] = (lo & 0xff00) >> 8;	addr[2] = (lo & 0xff0000) >> 16;	addr[3] = (lo & 0xff000000) >> 24;	addr[4] = (hi & 0xff);	addr[5] = (hi & 0xff00) >> 8;	if (is_valid_ether_addr(addr))	{		rt_memcpy(dev->dev_addr, &addr, 6);		return;	}	/* Check if bootloader set address in Specific-Address 2 */	hi = AT91_EMAC->EMAC_SA2H;	lo = AT91_EMAC->EMAC_SA2L;	addr[0] = (lo & 0xff);	addr[1] = (lo & 0xff00) >> 8;	addr[2] = (lo & 0xff0000) >> 16;	addr[3] = (lo & 0xff000000) >> 24;	addr[4] = (hi & 0xff);	addr[5] = (hi & 0xff00) >> 8;	if (is_valid_ether_addr(addr))	{		rt_memcpy(dev->dev_addr, &addr, 6);		return;	}	rt_memcpy(dev->dev_addr,&def_mac,6);	return;}/*

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -