📄 oaknet.c
字号:
/* * * 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; struct net_device tmp, *dev = NULL;#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; /* * This MUST happen here because of the nic_* macros * which have an implicit dependency on dev->base_addr. */ tmp.base_addr = ioaddr; dev = &tmp; ret = -EBUSY; if (!request_region(OAKNET_IO_BASE, OAKNET_IO_SIZE, name)) goto out_unmap; /* 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; } /* * We're not using the old-style probing API, so we have to allocate * our own device structure. */ dev = init_etherdev(NULL, 0); ret = -ENOMEM; if (!dev) goto out_region; SET_MODULE_OWNER(dev); oaknet_devs = 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; /* Allocate 8390-specific device-private area and fields. */ ret = -ENOMEM; if (ethdev_init(dev)) { printk(" unable to get memory for dev->priv.\n"); goto out_dev; } /* * 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", dev->name, dev->irq); goto out_priv; } /* 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; NS8390_init(dev, FALSE); return (0);out_priv: kfree(dev->priv);out_dev: unregister_netdev(dev); kfree(dev);out_region: release_region(OAKNET_IO_BASE, OAKNET_IO_SIZE);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. */ if (ei_status.dmaing) { oaknet_dma_error(dev, "oaknet_get_8390_hdr");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -