oaknet.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 666 行 · 第 1/2 页

C
666
字号
/* * *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu> * *    Module name: oaknet.c * *    Description: *      Driver for the National Semiconductor DP83902AV Ethernet controller *      on-board the IBM PowerPC "Oak" evaluation board. Adapted from the *      various other 8390 drivers written by Donald Becker and Paul Gortmaker. * *      Additional inspiration from the "tcd8390.c" driver from TiVo, Inc.  *      and "enetLib.c" from IBM. * */#include <linux/module.h>#include <linux/errno.h>#include <linux/delay.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/init.h>#include <asm/board.h>#include <asm/io.h>#include "8390.h"/* Preprocessor Defines */#if !defined(TRUE) || TRUE != 1#define	TRUE	1#endif#if !defined(FALSE) || FALSE != 0#define	FALSE	0#endif#define	OAKNET_START_PG		0x20	/* First page of TX buffer */#define	OAKNET_STOP_PG		0x40	/* Last pagge +1 of RX ring */#define	OAKNET_WAIT		(2 * HZ / 100)	/* 20 ms *//* Experimenting with some fixes for a broken driver... */#define	OAKNET_DISINT#define	OAKNET_HEADCHECK#define	OAKNET_RWFIX/* Global Variables */static const char *name = "National DP83902AV";static struct net_device *oaknet_devs;/* Function Prototypes */static int	 oaknet_open(struct net_device *dev);static int	 oaknet_close(struct net_device *dev);static void	 oaknet_reset_8390(struct net_device *dev);static void	 oaknet_get_8390_hdr(struct net_device *dev,				     struct e8390_pkt_hdr *hdr, int ring_page);static void	 oaknet_block_input(struct net_device *dev, int count,				    struct sk_buff *skb, int ring_offset);static void	 oaknet_block_output(struct net_device *dev, int count,				     const unsigned char *buf, int start_page);static void	 oaknet_dma_error(struct net_device *dev, const char *name);/* * int oaknet_init() * * Description: *   This routine performs all the necessary platform-specific initiali- *   zation and set-up for the IBM "Oak" evaluation board's National *   Semiconductor DP83902AV "ST-NIC" Ethernet controller. * * Input(s): *   N/A * * Output(s): *   N/A * * Returns: *   0 if OK, otherwise system error number on error. * */static int __init oaknet_init(void){	register int i;	int reg0, regd;	int ret = -ENOMEM;	struct net_device *dev;#if 0	unsigned long ioaddr = OAKNET_IO_BASE; #else	unsigned long ioaddr = ioremap(OAKNET_IO_BASE, OAKNET_IO_SIZE);#endif	bd_t *bip = (bd_t *)__res;	if (!ioaddr)		return -ENOMEM;	dev = alloc_ei_netdev();	if (!dev)		goto out_unmap;	ret = -EBUSY;	if (!request_region(OAKNET_IO_BASE, OAKNET_IO_SIZE, name))		goto out_dev;	/* Quick register check to see if the device is really there. */	ret = -ENODEV;	if ((reg0 = ei_ibp(ioaddr)) == 0xFF)		goto out_region;	/*	 * That worked. Now a more thorough check, using the multicast	 * address registers, that the device is definitely out there	 * and semi-functional.	 */	ei_obp(E8390_NODMA + E8390_PAGE1 + E8390_STOP, ioaddr + E8390_CMD);	regd = ei_ibp(ioaddr + 0x0D);	ei_obp(0xFF, ioaddr + 0x0D);	ei_obp(E8390_NODMA + E8390_PAGE0, ioaddr + E8390_CMD);	ei_ibp(ioaddr + EN0_COUNTER0);	/* It's no good. Fix things back up and leave. */	ret = -ENODEV;	if (ei_ibp(ioaddr + EN0_COUNTER0) != 0) {		ei_obp(reg0, ioaddr);		ei_obp(regd, ioaddr + 0x0D);		goto out_region;	}	SET_MODULE_OWNER(dev);	/*	 * This controller is on an embedded board, so the base address	 * and interrupt assignments are pre-assigned and unchageable.	 */	dev->base_addr = ioaddr;	dev->irq = OAKNET_INT;	/*	 * Disable all chip interrupts for now and ACK all pending	 * interrupts.	 */	ei_obp(0x0, ioaddr + EN0_IMR);	ei_obp(0xFF, ioaddr + EN0_ISR);	/* Attempt to get the interrupt line */	ret = -EAGAIN;	if (request_irq(dev->irq, ei_interrupt, 0, name, dev)) {		printk("%s: unable to request interrupt %d.\n",		       name, dev->irq);		goto out_region;	}	/* Tell the world about what and where we've found. */	printk("%s: %s at", dev->name, name);	for (i = 0; i < ETHER_ADDR_LEN; ++i) {		dev->dev_addr[i] = bip->bi_enetaddr[i];		printk("%c%.2x", (i ? ':' : ' '), dev->dev_addr[i]);	}	printk(", found at %#lx, using IRQ %d.\n", dev->base_addr, dev->irq);	/* Set up some required driver fields and then we're done. */	ei_status.name		= name;	ei_status.word16	= FALSE;	ei_status.tx_start_page	= OAKNET_START_PG;	ei_status.rx_start_page = OAKNET_START_PG + TX_PAGES;	ei_status.stop_page	= OAKNET_STOP_PG;	ei_status.reset_8390	= &oaknet_reset_8390;	ei_status.block_input	= &oaknet_block_input;	ei_status.block_output	= &oaknet_block_output;	ei_status.get_8390_hdr	= &oaknet_get_8390_hdr;	dev->open = oaknet_open;	dev->stop = oaknet_close;#ifdef CONFIG_NET_POLL_CONTROLLER	dev->poll_controller = ei_poll;#endif	NS8390_init(dev, FALSE);	ret = register_netdev(dev);	if (ret)		goto out_irq;		oaknet_devs = dev;	return 0;out_irq;	free_irq(dev->irq, dev);out_region:	release_region(OAKNET_IO_BASE, OAKNET_IO_SIZE);out_dev:	free_netdev(dev);out_unmap:	iounmap(ioaddr);	return ret;}/* * static int oaknet_open() * * Description: *   This routine is a modest wrapper around ei_open, the 8390-generic, *   driver open routine. This just increments the module usage count *   and passes along the status from ei_open. * * Input(s): *  *dev - Pointer to the device structure for this driver. * * Output(s): *  *dev - Pointer to the device structure for this driver, potentially *         modified by ei_open. * * Returns: *   0 if OK, otherwise < 0 on error. * */static intoaknet_open(struct net_device *dev){	int status = ei_open(dev);	return (status);}/* * static int oaknet_close() * * Description: *   This routine is a modest wrapper around ei_close, the 8390-generic, *   driver close routine. This just decrements the module usage count *   and passes along the status from ei_close. * * Input(s): *  *dev - Pointer to the device structure for this driver. * * Output(s): *  *dev - Pointer to the device structure for this driver, potentially *         modified by ei_close. * * Returns: *   0 if OK, otherwise < 0 on error. * */static intoaknet_close(struct net_device *dev){	int status = ei_close(dev);	return (status);}/* * static void oaknet_reset_8390() * * Description: *   This routine resets the DP83902 chip. * * Input(s): *  *dev - Pointer to the device structure for this driver. * * Output(s): *   N/A * * Returns: *   N/A * */static voidoaknet_reset_8390(struct net_device *dev){	int base = E8390_BASE;	/*	 * We have no provision of reseting the controller as is done	 * in other drivers, such as "ne.c". However, the following	 * seems to work well enough in the TiVo driver.	 */	printk("Resetting %s...\n", dev->name);	ei_obp(E8390_STOP | E8390_NODMA | E8390_PAGE0, base + E8390_CMD);	ei_status.txing = 0;	ei_status.dmaing = 0;}/* * static void oaknet_get_8390_hdr() * * Description: *   This routine grabs the 8390-specific header. It's similar to the *   block input routine, but we don't need to be concerned with ring wrap *   as the header will be at the start of a page, so we optimize accordingly. * * Input(s): *  *dev       - Pointer to the device structure for this driver. *  *hdr       - Pointer to storage for the 8390-specific packet header. *   ring_page - ? * * Output(s): *  *hdr       - Pointer to the 8390-specific packet header for the just- *               received frame. * * Returns: *   N/A * */static voidoaknet_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,		    int ring_page){	int base = dev->base_addr;	/*	 * This should NOT happen. If it does, it is the LAST thing you'll	 * see.	 */

⌨️ 快捷键说明

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