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

📄 ax88796b.c

📁 AX88796B的linux 2.4驱动
💻 C
📖 第 1 页 / 共 4 页
字号:

	ax_init (dev, 0);
	PRINTK (INIT_MSG,  PFX " probe end ..........\n");
	return 0;

err_out:
	iounmap (address);
	kfree (dev->priv);
	dev->priv = NULL;
	return ret;
}


#ifndef MODULE
/*
 * ----------------------------------------------------------------------------
 * Function Name: ax_kprobe
 * Purpose: 
 * Params:
 * Returns:
 * Note:
 * ----------------------------------------------------------------------------
 */
struct net_device * __init ax_kprobe (int unit)
{
	struct net_device *dev = alloc_ei_netdev ();
	int err;

	if (!dev)
		return ERR_PTR (-ENOMEM);

	sprintf (dev->name, "eth%d", unit);
	netdev_boot_setup_check (dev);

	err = ax_probe (dev);
	if (err)
		goto out;
	return dev;
out:
	free_netdev (dev);
	return ERR_PTR (err);
}
#endif


/*
 * ----------------------------------------------------------------------------
 * Function Name: ax_reset
 * Purpose: 
 * Params:
 * Returns:
 * Note:
 * ----------------------------------------------------------------------------
 */
static void ax_reset (struct net_device *dev)
{
    struct ax_device *ax_local = (struct ax_device *) dev->priv;
	void *ax_base = ax_local->membase;
	unsigned long reset_start_time = jiffies;
	readb (ax_base + EN0_RESET);

	ax_local->dmaing = 0;

	/* This check _should_not_ be necessary, omit eventually. */
	while ((readb (ax_base+EN0_ISR) & ENISR_RESET) == 0)
		if (jiffies - reset_start_time > 2*HZ/100) {
			PRINTK (ERROR_MSG, "%s: ax_reset() did not complete.\n", dev->name);
			break;
		}
	writeb (ENISR_RESET, ax_base + EN0_ISR);	/* Ack intr. */
}


/*
 * ----------------------------------------------------------------------------
 * Function Name: ax_get_hdr
 * Purpose: Grab the 796b specific header
 * Params:
 * Returns:
 * Note:
 * ----------------------------------------------------------------------------
 */
static void ax_get_hdr (struct net_device *dev, struct ax_pkt_hdr *hdr, int ring_page)
{
    struct ax_device *ax_local = (struct ax_device *) dev->priv;
	void *ax_base = ax_local->membase;
	u16 *buf = (u16 *)hdr;

	/* This *shouldn't* happen. If it does, it's the last thing you'll see */
	if (ax_local->dmaing)
	{
		PRINTK (ERROR_MSG, "%s: DMAing conflict in ne_get_8390_hdr "
			"[DMAstat:%d][irqlock:%d].\n",
			dev->name, ax_local->dmaing, ax_local->irqlock);
		return;
	}

	ax_local->dmaing |= 0x01;
	writeb (E8390_NODMA+E8390_PAGE0+E8390_START, ax_base+ E8390_CMD);
	writeb (sizeof (struct ax_pkt_hdr), ax_base + EN0_RCNTLO);
	writeb (0, ax_base + EN0_RCNTHI);
	writeb (0, ax_base + EN0_RSARLO);		/* On page boundary */
	writeb (ring_page, ax_base + EN0_RSARHI);
	writeb (E8390_RREAD+E8390_START, ax_base + E8390_CMD);

	while (( readb (ax_base+EN0_SR) & ENSR_DMA_READY) == 0);

	*buf = READ_FIFO (ax_base + EN0_DATAPORT);
	*(++buf) = READ_FIFO (ax_base + EN0_DATAPORT);

	writeb (ENISR_RDC, ax_base + EN0_ISR);	/* Ack intr. */
	ax_local->dmaing = 0;

	le16_to_cpus (&hdr->count);

}


/*
 * ----------------------------------------------------------------------------
 * Function Name: ax_block_input
 * Purpose:
 * Params:
 * Returns:
 * Note:
 * ----------------------------------------------------------------------------
 */
static void ax_block_input (struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
{
    struct ax_device *ax_local = (struct ax_device *) dev->priv;
	void *ax_base = ax_local->membase;
	u16 *buf = (u16 *)skb->data;
	u16 i;

	/* This *shouldn't* happen. If it does, it's the last thing you'll see */
	if (ax_local->dmaing)
	{
		PRINTK (ERROR_MSG, "%s: DMAing conflict in ne_block_input "
			"[DMAstat:%d][irqlock:%d].\n",
			dev->name, ax_local->dmaing, ax_local->irqlock);
		return;
	}

	ax_local->dmaing |= 0x01;
	writeb (E8390_NODMA+E8390_PAGE0+E8390_START, ax_base+ E8390_CMD);
	writeb (count & 0xff, ax_base + EN0_RCNTLO);
	writeb (count >> 8, ax_base + EN0_RCNTHI);
	writeb (ring_offset & 0xff, ax_base + EN0_RSARLO);
	writeb (ring_offset >> 8, ax_base + EN0_RSARHI);
	writeb (E8390_RREAD+E8390_START, ax_base + E8390_CMD);

	while (( readb (ax_base+EN0_SR) & ENSR_DMA_READY) == 0);

#if (CONFIG_AX88796B_USE_MEMCPY == 1)
	{
		/* make the burst length be divided for 32-bit */
		i = ((count - 2) + 3) & 0x7FC;

		/* Read first 2 bytes */
		*buf = READ_FIFO (ax_base + EN0_DATAPORT);

		/* The address of ++buf should be agigned on 32-bit boundary */
		memcpy (++buf, ax_base+EN0_DATA_ADDR, i);
	}
#else
	{
		for (i = 0; i < count; i += 2) {
			*buf++ = READ_FIFO (ax_base + EN0_DATAPORT);
		}
	}
#endif

	writeb (ENISR_RDC, ax_base + EN0_ISR);	/* Ack intr. */
	ax_local->dmaing = 0;
}


/*
 * ----------------------------------------------------------------------------
 * Function Name: ax_block_output
 * Purpose:
 * Params:
 * Returns:
 * Note:
 * ----------------------------------------------------------------------------
 */
static void ax_block_output (struct net_device *dev, int count, const unsigned char *buf, const int start_page)
{
    struct ax_device *ax_local = (struct ax_device *) dev->priv;
	void *ax_base = ax_local->membase;
	unsigned long dma_start;

	/* This *shouldn't* happen. If it does, it's the last thing you'll see */
	if (ax_local->dmaing)
	{
		PRINTK (ERROR_MSG, "%s: DMAing conflict in ne_block_output."
			"[DMAstat:%d][irqlock:%d]\n",
			dev->name, ax_local->dmaing, ax_local->irqlock);
		return;
	}

	ax_local->dmaing |= 0x01;
	/* We should already be in page 0, but to be safe... */
	writeb (E8390_PAGE0+E8390_START+E8390_NODMA, ax_base + E8390_CMD);
	writeb (ENISR_RDC, ax_base + EN0_ISR);
	/* Now the normal output. */
	writeb (count & 0xff, ax_base + EN0_RCNTLO);
	writeb (count >> 8,   ax_base + EN0_RCNTHI);
	writeb (0x00, ax_base + EN0_RSARLO);
	writeb (start_page, ax_base + EN0_RSARHI);
	writeb (E8390_RWRITE+E8390_START, ax_base + E8390_CMD);

#if (CONFIG_AX88796B_USE_MEMCPY == 1)
	memcpy ((ax_base+EN0_DATA_ADDR), buf, ((count+ 3) & 0x7FC));
#else
	{
		u16 i;
		for (i = 0; i < count; i += 2) {
			WRITE_FIFO (ax_base + EN0_DATAPORT, *((u16 *)(buf + i)));
		}
	}
#endif
	dma_start = jiffies;
	while ((readb(ax_base + EN0_ISR) & 0x40) == 0) {
		if (jiffies - dma_start > 2*HZ/100) {		/* 20ms */
			PRINTK (ERROR_MSG, "%s: timeout waiting for Tx RDC.\n", dev->name);
			ax_reset (dev);
			ax_init (dev,1);
			break;
		}
	}
	writeb (ENISR_RDC, ax_base + EN0_ISR);	/* Ack intr. */
	ax_local->dmaing = 0;
	return;
}


/*
 * ----------------------------------------------------------------------------
 * Function Name: ax_open
 * Purpose: Open/initialize 796b
 * Params:
 * Returns:
 * Note:
 * ----------------------------------------------------------------------------
 */
static int ax_open (struct net_device *dev)
{
	unsigned long flags;
	struct ax_device *ax_local = (struct ax_device *) dev->priv;
	void *membase = ax_local->membase;
	int ret=0;

	PRINTK (DEBUG_MSG, PFX " ax88796B ei_open beginning ..........\n");
	PRINTK (DEBUG_MSG, PFX " membase %p\n\r", membase);

	ret = request_irq (dev->irq, &ax_interrupt, 0, dev->name, dev);

	if (ret) {
		PRINTK (ERROR_MSG, "%s: unable to get IRQ %d (errno=%d).\n",dev->name, dev->irq, ret);
		return -ENXIO;
	}

	PRINTK (DEBUG_MSG, PFX " Request IRQ success !!\n\r");

	/* This can't happen unless somebody forgot to call ethdev_init(). */
	if (ax_local == NULL) 
	{
		PRINTK (ERROR_MSG, "%s: ei_open passed a non-existent device!\n", dev->name);
		return -ENXIO;
	}

	dev->tx_timeout = NULL;
	dev->watchdog_timeo = 0;

    spin_lock_irqsave (&ax_local->page_lock, flags);
	ax_reset (dev);
	ax_init (dev, 1);
	netif_start_queue (dev);
    spin_unlock_irqrestore (&ax_local->page_lock, flags);
	ax_local->irqlock = 0;

	init_timer (&ax_local->watchdog);
	ax_local->watchdog.function = &ax_watchdog;
	ax_local->watchdog.expires = jiffies + AX88796_WATCHDOG_PERIOD;
	ax_local->watchdog.data = (unsigned long) dev;
	add_timer (&ax_local->watchdog);

	PRINTK (DEBUG_MSG, PFX " ax88796B ei_open end ..........\n");

	return 0;
}


/*
 * ----------------------------------------------------------------------------
 * Function Name: ax_close
 * Purpose:
 * Params:
 * Returns:
 * Note:
 * ----------------------------------------------------------------------------
 */
static int ax_close (struct net_device *dev)
{
	struct ax_device *ax_local = (struct ax_device *) dev->priv;
	unsigned long flags;
 	PRINTK (DEBUG_MSG, PFX " ax88796B ei_close beginning ..........\n");
	del_timer (&ax_local->watchdog);
   	spin_lock_irqsave (&ax_local->page_lock, flags);
	ax_init (dev, 0);

	free_irq (dev->irq, dev);

   	spin_unlock_irqrestore (&ax_local->page_lock, flags);
	netif_stop_queue (dev);
	PRINTK (DEBUG_MSG, PFX " ax88796B ei_close end ..........\n");
	return 0;
}


/*
 * ----------------------------------------------------------------------------
 * Function Name: ax_start_xmit
 * Purpose: begin packet transmission
 * Params:
 * Returns:
 * Note:
 * ----------------------------------------------------------------------------
 */
static int ax_start_xmit (struct sk_buff *skb, struct net_device *dev)
{
	struct ax_device *ax_local = (struct ax_device *) dev->priv;
	void *ax_base = ax_local->membase;
	int send_length;
	unsigned long flags;
	u8 ctepr=0, free_pages=0, need_pages;

	/* check for link status */
	if (!(readb (ax_base + EN0_SR) & ENSR_LINK)) {
		dev_kfree_skb (skb);
		return 0;
	}

	send_length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;

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

	spin_lock (&ax_local->page_lock);
	ax_local->irqlock = 1;

	need_pages = (send_length -1)/256 +1;
	ctepr = readb (ax_base + EN0_CTEPR) & 0x7f;
		
	if (ctepr == 0) {
		if (ax_local->tx_curr_page == ax_local->tx_start_page && ax_local->tx_prev_ctepr == 0)
			free_pages = TX_PAGES;
		else
			free_pages = ax_local->tx_stop_page - ax_local->tx_curr_page;
	}
	else if (ctepr < ax_local->tx_curr_page - 1) {
		free_pages = ax_local->tx_stop_page - ax_local->tx_curr_page + 
					 ctepr - ax_local->tx_start_page + 1;
	}
	else if (ctepr > ax_local->tx_curr_page - 1) {
		free_pages = ctepr + 1 - ax_local->tx_curr_page;
	}
	else if (ctepr == ax_local->tx_curr_page - 1) {
		if (ax_local->tx_full)
			free_pages = 0;
		else
			free_pages = TX_PAGES;
	}		

	if (free_pages < need_pages) {
		PRINTK (DEBUG_MSG, "free_pages < need_pages\n\r");
		netif_stop_queue (dev);
		ax_local->tx_full = 1;
		ax_local->irqlock = 0;	
		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);
		return 1;
	}

	ax_block_output (dev, send_length, skb->data, ax_local->tx_curr_page);
	ax_trigger_send (dev, send_length, ax_local->tx_curr_page);
	if (free_pages == need_pages) {
		netif_stop_queue (dev);
		ax_local->tx_full = 1;
	}
	ax_local->tx_prev_ctepr = ctepr;
	ax_local->tx_curr_page = ax_local->tx_curr_page + need_pages < ax_local->tx_stop_page ? 
	ax_local->tx_curr_page + need_pages : 
	need_pages - (ax_local->tx_stop_page - ax_local->tx_curr_page) + ax_local->tx_start_page;

	dev_kfree_skb (skb);
	dev->trans_start = jiffies;
	ax_local->stat.tx_bytes += send_length;

	ax_local->irqlock = 0;	
	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);
	return 0;
}


/*
 * ----------------------------------------------------------------------------
 * Function Name: ax_tx_intr
 * Purpose:
 * Params:
 * Returns:
 * Note:
 * ----------------------------------------------------------------------------
 */
static void ax_tx_intr (struct net_device *dev)
{
    struct ax_device *ax_local = (struct ax_device *) dev->priv;
	void *ax_base = ax_local->membase;
	int status = readb (ax_base + EN0_TSR);

	ax_local->tx_full = 0;
	if (netif_queue_stopped (dev))
		netif_wake_queue (dev);

	/* Minimize Tx latency: update the statistics after we restart TXing. */
	if (status & ENTSR_COL)
		ax_local->stat.collisions++;
	if (status & ENTSR_PTX)
		ax_local->stat.tx_packets++;
	else 
	{
		ax_local->stat.tx_errors++;
		if (status & ENTSR_ABT) 
		{
			ax_local->stat.tx_aborted_errors++;
			ax_local->stat.collisions += 16;
		}
		if (status & ENTSR_CRS) 
			ax_local->stat.tx_carrier_errors++;
		if (status & ENTSR_FU) 
			ax_local->stat.tx_fifo_errors++;
		if (status & ENTSR_CDH)
			ax_local->stat.tx_heartbeat_errors++;
		if (status & ENTSR_OWC)
			ax_local->stat.tx_window_errors++;
	}
}


/*
 * ----------------------------------------------------------------------------
 * Function Name: ax_interrupt
 * Purpose:
 * Params:
 * Returns:
 * Note:
 * ----------------------------------------------------------------------------
 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
static void ax_interrupt (int irq, void *dev_id, struct pt_regs * regs)
#else
static irqreturn_t ax_interrupt (int irq, void *dev_id, struct pt_regs * regs)
#endif
{
	struct net_device *dev = dev_id;
	int interrupts;
       struct ax_device *ax_local = (struct ax_device *) dev->priv;
	void *ax_base = ax_local->membase;
	unsigned long flags;

⌨️ 快捷键说明

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