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

📄 ax88796b.c

📁 AX88796B的linux 2.4驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
	if (dev == NULL) 
	{
		PRINTK (ERROR_MSG, "net_interrupt(): irq %d for unknown device.\n", irq);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
		return;
#else
		return 0;
#endif
	}

	writeb (E8390_NODMA+E8390_PAGE0, ax_base + E8390_CMD);

	spin_lock_irqsave (&ax_local->page_lock, flags);
		writeb (0x00, ax_base + EN0_IMR);
	spin_unlock_irqrestore (&ax_local->page_lock, flags);

	if (ax_local->irqlock) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
		return;
#else
		return 0;
#endif
	}

	spin_lock (&ax_local->page_lock);
	
	while (1)
	{

		if ((interrupts = readb (ax_base + EN0_ISR)) == 0)
			break;
		
		writeb (interrupts, ax_base + EN0_ISR); /* Ack the interrupts */

		if (interrupts & ENISR_TX)
			ax_tx_intr (dev);

		if (interrupts & ENISR_OVER)
			ax_rx_overrun (dev);
		
		if (interrupts & (ENISR_RX+ENISR_RX_ERR))
			ax_receive (dev);

		if (interrupts & ENISR_TX_ERR)
			ax_tx_err (dev);

		if (interrupts & ENISR_COUNTERS) 
		{   
			ax_local->stat.rx_frame_errors += readb (ax_base + EN0_COUNTER0);
			ax_local->stat.rx_crc_errors   += readb (ax_base + EN0_COUNTER1);
			ax_local->stat.rx_missed_errors+= readb (ax_base + EN0_COUNTER2); 
			writeb (ENISR_COUNTERS, ax_base + EN0_ISR); /* Ack intr. */
		}

		if (interrupts & ENISR_RDC)
			writeb (ENISR_RDC, ax_base + EN0_ISR);
		
		writeb (E8390_NODMA+E8390_PAGE0+E8390_START, ax_base + E8390_CMD);
	}

	spin_unlock (&ax_local->page_lock);
	spin_lock_irqsave (&ax_local->page_lock, flags);
		writeb (ENISR_ALL, ax_base + EN0_IMR);
	spin_unlock_irqrestore (&ax_local->page_lock, flags);

	writeb (E8390_NODMA+E8390_PAGE0+E8390_START, ax_base + E8390_CMD);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
	return;
#else
	return IRQ_RETVAL (0);
#endif
}


/*
 * ----------------------------------------------------------------------------
 * Function Name: ax_tx_err
 * Purpose:
 * Params:
 * Returns:
 * Note:
 * ----------------------------------------------------------------------------
 */
static void ax_tx_err (struct net_device *dev)
{
    struct ax_device *ax_local = (struct ax_device *) dev->priv;
	void *ax_base = ax_local->membase;

	unsigned char txsr = readb (ax_base+EN0_TSR);
	unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU);

	if (tx_was_aborted)
		ax_tx_intr (dev);
	else 
	{
		ax_local->stat.tx_errors++;
		if (txsr & ENTSR_CRS) ax_local->stat.tx_carrier_errors++;
		if (txsr & ENTSR_CDH) ax_local->stat.tx_heartbeat_errors++;
		if (txsr & ENTSR_OWC) ax_local->stat.tx_window_errors++;
	}
}


/*
 * ----------------------------------------------------------------------------
 * Function Name: ax_receive
 * Purpose:
 * Params:
 * Returns:
 * Note:
 * ----------------------------------------------------------------------------
 */
static void ax_receive (struct net_device *dev)
{
    struct ax_device *ax_local = (struct ax_device *) dev->priv;
	void *ax_base = ax_local->membase;
	unsigned char rxing_page, this_frame, next_frame;
	unsigned short current_offset;
	struct ax_pkt_hdr rx_frame;
	int num_rx_pages = ax_local->stop_page - ax_local->rx_start_page;
	while (1)
	{
		int pkt_len, pkt_stat;

		/* Get the rx page (incoming packet pointer). */
		writeb (E8390_NODMA+E8390_PAGE1, ax_base + E8390_CMD);
		rxing_page = readb (ax_base + EN1_CURPAG);
		writeb (E8390_NODMA+E8390_PAGE0, ax_base + E8390_CMD);

		/* Remove one frame from the ring.  Boundary is always a page behind. */
		this_frame = readb (ax_base + EN0_BOUNDARY) + 1;
		if (this_frame >= ax_local->stop_page)
			this_frame = ax_local->rx_start_page;

		if (this_frame != ax_local->current_page && (this_frame!=0x0 || rxing_page!=0xFF))
			PRINTK (RX_MSG, "%s: mismatched read page pointers %2x vs %2x.\n",
				   dev->name, this_frame, ax_local->current_page);
		
		if (this_frame == rxing_page) {	/* Read all the frames? */
			break;				/* Done for now */
		}
		current_offset = this_frame << 8;
		ax_get_hdr (dev, &rx_frame, this_frame);

		pkt_len = rx_frame.count - sizeof (struct ax_pkt_hdr);
		pkt_stat = rx_frame.status;
		next_frame = this_frame + 1 + ((pkt_len+4)>>8);
		
		/* Check for bogosity warned by 3c503 book: the status byte is never
		   written.  This happened a lot during testing! This code should be
		   cleaned up someday. */
		if (rx_frame.next != next_frame
			&& rx_frame.next != next_frame + 1
			&& rx_frame.next != next_frame - num_rx_pages
			&& rx_frame.next != next_frame + 1 - num_rx_pages) {
			ax_local->current_page = rxing_page;
			writeb (ax_local->current_page-1, ax_base+EN0_BOUNDARY);
			ax_local->stat.rx_errors++;
			PRINTK (ERROR_MSG, "error occurred! Drop this packet!!\n");
			continue;
		}

		if (pkt_len < 60  ||  pkt_len > 1518)
		{
			PRINTK (RX_MSG, "%s: bogus packet size: %d, status=%#2x nxpg=%#2x.\n",
					   dev->name, rx_frame.count, rx_frame.status,
					   rx_frame.next);
			ax_local->stat.rx_errors++;
			ax_local->stat.rx_length_errors++;
		}
		else if ((pkt_stat & 0x0F) == ENRSR_RXOK) 
		{
			struct sk_buff *skb;
			skb = dev_alloc_skb (pkt_len+2);
			if (skb == NULL)
			{
				printk ("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, pkt_len);
				ax_local->stat.rx_dropped++;
				break;
			}
			skb_reserve (skb, 2);	/* IP headers on 16 byte boundaries */
			skb->dev = dev;
			skb_put (skb, pkt_len);	/* Make room */
			ax_block_input (dev, pkt_len, skb, current_offset + sizeof (rx_frame));
			skb->protocol = eth_type_trans (skb,dev);
			netif_rx (skb);
			dev->last_rx = jiffies;
			ax_local->stat.rx_packets++;
			ax_local->stat.rx_bytes += pkt_len;
			if (pkt_stat & ENRSR_PHY)
				ax_local->stat.multicast++;
		}
		else 
		{
			PRINTK (ERROR_MSG, "%s: bogus packet: status=%#2x nxpg=%#2x size=%d\n",
					   dev->name, rx_frame.status, rx_frame.next, rx_frame.count);
			ax_local->stat.rx_errors++;
			/* NB: The NIC counts CRC, frame and missed errors. */
			if (pkt_stat & ENRSR_FO)
				ax_local->stat.rx_fifo_errors++;
		}
		next_frame = rx_frame.next;
		
		/* This _should_ never happen: it's here for avoiding bad clones. */
		if (next_frame >= ax_local->stop_page) {
			PRINTK (ERROR_MSG, "%s: next frame inconsistency, %#2x\n", dev->name, next_frame);
			next_frame = ax_local->rx_start_page;
		}
		ax_local->current_page = next_frame;
		writeb (next_frame-1, ax_base+EN0_BOUNDARY);
	}

	return;
}

/*
 * ----------------------------------------------------------------------------
 * Function Name: ax_rx_overrun
 * Purpose:
 * Params:
 * Returns:
 * Note:
 * ----------------------------------------------------------------------------
 */
static void ax_rx_overrun (struct net_device *dev)
{
    struct ax_device *ax_local = (struct ax_device *) dev->priv;
	void *ax_base = ax_local->membase;
	unsigned char was_txing, must_resend = 0;

    
	/*
	 * Record whether a Tx was in progress and then issue the
	 * stop command.
	 */
	was_txing = readb (ax_base+E8390_CMD) & E8390_TRANS;
	writeb (E8390_NODMA+E8390_PAGE0+E8390_STOP, ax_base+E8390_CMD);

	PRINTK (RX_MSG, "%s: Receiver overrun.\n", dev->name);

	ax_local->stat.rx_over_errors++;

	udelay (2*1000);

	writeb (0x00, ax_base+EN0_RCNTLO);
	writeb (0x00, ax_base+EN0_RCNTHI);

	/*
	 * See if any Tx was interrupted or not. According to NS, this
	 * step is vital, and skipping it will cause no end of havoc.
	 */

	if (was_txing)
	{ 
		unsigned char tx_completed = readb (ax_base+EN0_ISR) & (ENISR_TX+ENISR_TX_ERR);
		if (!tx_completed)
			must_resend = 1;
	}

	/*
	 * Have to enter loopback mode and then restart the NIC before
	 * you are allowed to slurp packets up off the ring.
	 */
	writeb (E8390_TXOFF, ax_base + EN0_TXCR);
	writeb (E8390_NODMA + E8390_PAGE0 + E8390_START, ax_base + E8390_CMD);

	/*
	 * Clear the Rx ring of all the debris, and ack the interrupt.
	 */
	ax_receive (dev);

	/*
	 * Leave loopback mode, and resend any packet that got stopped.
	 */
	writeb (E8390_TXCONFIG, ax_base + EN0_TXCR); 
	if (must_resend)
    	writeb (E8390_NODMA + E8390_PAGE0 + E8390_START + E8390_TRANS, ax_base + E8390_CMD);

}


/*
 *	Collect the stats. This is called unlocked and from several contexts.
 */
static struct net_device_stats *get_stats (struct net_device *dev)
{
 	struct ax_device *ax_local = (struct ax_device *) dev->priv;
	void *ax_base = ax_local->membase; 
	unsigned long flags;

	/* If the card is stopped, just return the present stats. */
	if (!netif_running (dev))
		return &ax_local->stat;

	spin_lock_irqsave (&ax_local->page_lock,flags);
	/* Read the counter registers, assuming we are in page 0. */
	ax_local->stat.rx_frame_errors += readb (ax_base + EN0_COUNTER0);
	ax_local->stat.rx_crc_errors   += readb (ax_base + EN0_COUNTER1);
	ax_local->stat.rx_missed_errors+= readb (ax_base + EN0_COUNTER2);

	spin_unlock_irqrestore (&ax_local->page_lock, flags);
	return &ax_local->stat;
}


/*
 * ----------------------------------------------------------------------------
 * Function Name: make_mc_bits
 * Purpose:
 * Params:
 * Returns:
 * Note:
 * ----------------------------------------------------------------------------
 */
static inline void make_mc_bits (u8 *bits, struct net_device *dev)
{
	struct dev_mc_list *dmi;
	for (dmi=dev->mc_list; dmi; dmi=dmi->next) 
	{
		u32 crc;
		if (dmi->dmi_addrlen != ETH_ALEN) 
		{
			PRINTK (INIT_MSG, "%s: invalid multicast address length given.\n", dev->name);
			continue;
		}
		crc = ether_crc (ETH_ALEN, dmi->dmi_addr);
		/* 
		 * The 8390 uses the 6 most significant bits of the
		 * CRC to index the multicast table.
		 */
		bits[crc>>29] |= (1<<((crc>>26)&7));
	}
}


/*
 * ----------------------------------------------------------------------------
 * Function Name: do_set_multicast_list
 * Purpose:
 * Params:
 * Returns:
 * Note:
 * ----------------------------------------------------------------------------
 */
static void do_set_multicast_list (struct net_device *dev)
{
 	struct ax_device *ax_local = (struct ax_device *) dev->priv;
	void *ax_base = ax_local->membase; 
	int i;
	if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) 
	{
		memset (ax_local->mcfilter, 0, 8);
		if (dev->mc_list)
			make_mc_bits (ax_local->mcfilter, dev);
	}
	else
		memset (ax_local->mcfilter, 0xFF, 8);	/* mcast set to accept-all */
	 
	if (netif_running (dev))
		writeb (E8390_RXCONFIG, ax_base + EN0_RXCR);
	writeb (E8390_NODMA + E8390_PAGE1, ax_base + E8390_CMD);
	for (i = 0; i < 8; i++) 
	{
		writeb (ax_local->mcfilter[i], ax_base + EN1_MULT_SHIFT (i));
	}
	writeb (E8390_NODMA + E8390_PAGE0, ax_base + E8390_CMD);

  	if (dev->flags&IFF_PROMISC)
  		writeb (E8390_RXCONFIG | 0x18, ax_base + EN0_RXCR);
	else if (dev->flags&IFF_ALLMULTI || dev->mc_list) 
  		writeb (E8390_RXCONFIG | 0x08, ax_base + EN0_RXCR);
	
	else 
  		writeb (E8390_RXCONFIG, ax_base + EN0_RXCR);
 }


/*
 * ----------------------------------------------------------------------------
 * Function Name: set_multicast_list
 * Purpose:
 * Params:
 * Returns:
 * Note:
 * ----------------------------------------------------------------------------
 */
static void set_multicast_list (struct net_device *dev)
{
	unsigned long flags;
	struct ax_device *ax_local = (struct ax_device*)dev->priv;
	
	spin_lock_irqsave (&ax_local->page_lock, flags);
	do_set_multicast_list (dev);
	spin_unlock_irqrestore (&ax_local->page_lock, flags);
}	


/*
 * ----------------------------------------------------------------------------
 * Function Name: ethdev_init
 * Purpose:
 * Params:
 * Returns:
 * Note:
 * ----------------------------------------------------------------------------
 */
static int ethdev_init (struct net_device *dev)
{
  
	if (dev->priv == NULL) 
	{
		struct ax_device *ax_local;
		
		dev->priv = kmalloc (sizeof (struct ax_device), GFP_KERNEL);
		if (dev->priv == NULL)
			return -ENOMEM;
		memset (dev->priv, 0, sizeof (struct ax_device));
		ax_local = (struct ax_device *)dev->priv;
		spin_lock_init (&ax_local->page_lock);
	}
    
	dev->hard_start_xmit = &ax_start_xmit;
	dev->get_stats	= get_stats;
	dev->set_multicast_list = &set_multicast_list;

	ether_setup (dev);
        
	return 0;
}


/*
 * ----------------------------------------------------------------------------
 * Function Name: ax88796_PHY_init
 * Purpose:
 * Params:
 * Returns:
 * Note:
 * ----------------------------------------------------------------------------
 */
void ax88796_PHY_init (struct net_device *dev)
{
	struct ax_device *ax_local = (struct ax_device *) dev->priv;
	void *ax_base = ax_local->membase;
	u16 advertise;

	/* Enable AX88796B FOLW CONTROL */
	writeb (ENFLOW_ENABLE, ax_base+EN0_FLOW);

	advertise = mdio_read (dev, 0x10, MII_ADVERTISE) & ~ADVERTISE_ALL;

	switch (ax_local->media) {
	case MEDIA_AUTO:
		PRINTK (DRIVER_MSG, PFX " The media mode is autosense.\n");
		advertise |= ADVERTISE_ALL | 0x400;
		break;

	case MEDIA_100FULL:
		PRINTK (DRIVER_MSG, PFX " The media mode is forced to 100full.\n");
		advertise |= ADVERTISE_100FULL | 0x400;
		break;

	case MEDIA_100HALF:
		PRINTK (DRIVER_MSG, PFX " The media mode is forced to 100half.\n");
		advertise |= ADVERTISE_100HALF;
		break;

	case MEDIA_10FULL:
		PRINTK (DRIVER_MSG, PFX " The media mode is forced to 10full.\n");
		advertise |= ADVERTISE_10FULL;
		break;

	case MEDIA_10HALF:
		PRINTK (DRIVER_MSG, PFX " The media mode is forced to 10half.\n");
		advertise |= ADVERTISE_10HALF;
		break;
	default:
		advertise |= ADVERTISE_ALL | 0x400;
		break;

⌨️ 快捷键说明

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