📄 hydra.c
字号:
/* Linux/68k Hydra Amiganet board driver v2.1 BETA *//* copyleft by Topi Kanerva (topi@susanna.oulu.fi) *//* also some code & lots of fixes by Timo Rossi (trossi@cc.jyu.fi) *//* The code is mostly based on the linux/68k Ariadne driver *//* copyrighted by Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be) *//* and Peter De Schrijver (Peter.DeSchrijver@linux.cc.kuleuven.ac.be) *//* This file is subject to the terms and conditions of the GNU General *//* Public License. See the file COPYING in the main directory of the *//* Linux distribution for more details. *//* The Amiganet is a Zorro-II board made by Hydra Systems. It contains a *//* NS8390 NIC (network interface controller) clone, 16 or 64K on-board RAM *//* and 10BASE-2 (thin coax) and AUI connectors. */#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/ptrace.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/malloc.h>#include <linux/interrupt.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/init.h>#include <asm/bitops.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/amigaints.h>#include <asm/amigahw.h>#include <linux/zorro.h>#include "hydra.h"#define HYDRA_DEBUG#undef HAVE_MULTICAST#define HYDRA_VERSION "v2.1 BETA"#undef HYDRA_DEBUG /* define this for (lots of) debugging information */#if 0 /* currently hardwired to one transmit buffer */ #define TX_RING_SIZE 5 #define RX_RING_SIZE 16#else #define TX_RING_SIZE 1 #define RX_RING_SIZE 8#endif#define ETHER_MIN_LEN 64#define ETHER_MAX_LEN 1518#define ETHER_ADDR_LEN 6/* * let's define here nice macros for writing and reading NIC registers * * the CIA accesses here are uses to make sure the minimum time * requirement between NIC chip selects is met. */#define WRITE_REG(reg, val) (ciaa.pra, ((u8)(*(nicbase+(reg))=val)))#define READ_REG(reg) (ciaa.pra, ((u8)(*(nicbase+(reg)))))/* mask value for the interrupts we use */#define NIC_INTS (ISR_PRX | ISR_PTX | ISR_RXE | ISR_TXE | ISR_OVW | ISR_CNT)/* only broadcasts, no promiscuous mode for now */#define NIC_RCRBITS (0)/* * Private Device Data */struct hydra_private{ u8 *hydra_base; u8 *hydra_nic_base; u16 tx_page_start; u16 rx_page_start; u16 rx_page_stop; u16 next_pkt; struct net_device_stats stats; unsigned int key;};static int hydra_open(struct device *dev);static int hydra_start_xmit(struct sk_buff *skb, struct device *dev);static void hydra_interrupt(int irq, void *data, struct pt_regs *fp);static void __inline__ hydra_rx(struct device *dev, struct hydra_private *priv, volatile u8 *nicbase);static int hydra_close(struct device *dev);static struct net_device_stats *hydra_get_stats(struct device *dev);#ifdef HAVE_MULTICASTstatic void set_multicast_list(struct device *dev, int num_addrs, void *addrs);#endif/* this is now coherent with the C version below, *//* compile the source with -D__USE_ASM__ if you *//* want it - it'll only be some 10% faster though */#if defined (__GNUC__) && defined (__mc68000__) && defined (USE_ASM)static __inline__ void *memcpyw(u16 *dest, u16 *src, int len){ __asm__(" move.l %0,%/a1; move.l %1,%/a0; move.l %2,%/d0 \n\t" " cmpi.l #2,%/d0 \n\t" "1: bcs.s 2f \n\t" " move.w %/a0@+,%/a1@+ \n\t" " subq.l #2,%/d0 \n\t" " bra.s 1b \n\t" "2: cmpi.l #1,%/d0 \n\t" " bne.s 3f \n\t" " move.w %/a0@,%/d0 \n\t" " swap.w %/d0 \n\t" " move.b %/d0,%/a1@ \n\t" "3: moveq #0,%/d0 \n\t" : : "g" (dest), "g" (src), "g" (len) : "a1", "a0", "d0"); return;}#else/* hydra memory can only be read or written as words or longwords. *//* that will mean that we'll have to write a special memcpy for it. *//* this one here relies on the fact that _writes_ to hydra memory *//* are guaranteed to be of even length. (reads can be arbitrary) *//* * FIXME: Surely we should be using the OS generic stuff and do * * memcpy(dest,src,(len+1)&~1); * * Can a 68K guy with this card check that ? - better yet * use a copy/checksum on it. */ static void memcpyw(u16 *dest, u16 *src, int len){ if(len & 1) len++; while (len >= 2) { *(dest++) = *(src++); len -= 2; }}#endif__initfunc(int hydra_probe(struct device *dev)){ struct hydra_private *priv; u32 board; unsigned int key; const struct ConfigDev *cd; int j;#ifdef HYDRA_DEBUG printk("hydra_probe(%x)\n", dev);#endif if ((key = zorro_find(ZORRO_PROD_HYDRA_SYSTEMS_AMIGANET, 0, 0))) { cd = zorro_get_board(key); if((board = (u32) cd->cd_BoardAddr)) { for(j = 0; j < ETHER_ADDR_LEN; j++) dev->dev_addr[j] = *((u8 *)ZTWO_VADDR(board + HYDRA_ADDRPROM + 2*j)); printk("%s: hydra at 0x%08x, address %02x:%02x:%02x:%02x:%02x:%02x (hydra.c " HYDRA_VERSION ")\n", dev->name, (int)board, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); init_etherdev(dev, 0); dev->priv = kmalloc(sizeof(struct hydra_private), GFP_KERNEL); priv = (struct hydra_private *)dev->priv; memset(priv, 0, sizeof(struct hydra_private)); priv->hydra_base = (u8 *) ZTWO_VADDR(board); priv->hydra_nic_base = (u8 *) ZTWO_VADDR(board) + HYDRA_NIC_BASE; priv->key = key; dev->open = &hydra_open; dev->stop = &hydra_close; dev->hard_start_xmit = &hydra_start_xmit; dev->get_stats = &hydra_get_stats;#ifdef HAVE_MULTICAST dev->set_multicast_list = &set_multicast_list;#endif /* * Cannot yet do multicast */ dev->flags&=~IFF_MULTICAST; zorro_config_board(key, 0); return(0); } } return(-ENODEV);}static int hydra_open(struct device *dev){ struct hydra_private *priv = (struct hydra_private *)dev->priv; volatile u8 *nicbase = priv->hydra_nic_base; int i; #ifdef HYDRA_DEBUG printk("hydra_open(0x%x)\n", dev);#endif /* first, initialize the private structure */ priv->tx_page_start = 0; /* these are 256 byte buffers for NS8390 */ priv->rx_page_start = 6; priv->rx_page_stop = 62; /* these values are hard coded for now */ /* Reset the NS8390 NIC */ WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_STOP); /* be sure that the NIC is in stopped state */ while(!(READ_REG(NIC_ISR) & ISR_RST)); /* word transfer, big endian bytes, loopback, FIFO threshold 4 bytes */ WRITE_REG(NIC_DCR, DCR_WTS | DCR_BOS | DCR_LS | DCR_FT0); /* clear remote byte count registers */ WRITE_REG(NIC_RBCR0, 0); WRITE_REG(NIC_RBCR1, 0); /* accept packets addressed to this card and also broadcast packets */ WRITE_REG(NIC_RCR, NIC_RCRBITS); /* enable loopback mode 1 */ WRITE_REG(NIC_TCR, TCR_LB1); /* initialize receive buffer ring */ WRITE_REG(NIC_PSTART, priv->rx_page_start); WRITE_REG(NIC_PSTOP, priv->rx_page_stop); WRITE_REG(NIC_BNDRY, priv->rx_page_start); /* clear interrupts */ WRITE_REG(NIC_ISR, 0xff); /* enable interrupts */ WRITE_REG(NIC_IMR, NIC_INTS); /* set the ethernet hardware address */ WRITE_REG(NIC_CR, CR_PAGE1 | CR_NODMA | CR_STOP); /* goto page 1 */ WRITE_REG(NIC_PAR0, dev->dev_addr[0]); WRITE_REG(NIC_PAR1, dev->dev_addr[1]); WRITE_REG(NIC_PAR2, dev->dev_addr[2]); WRITE_REG(NIC_PAR3, dev->dev_addr[3]); WRITE_REG(NIC_PAR4, dev->dev_addr[4]); WRITE_REG(NIC_PAR5, dev->dev_addr[5]); /* clear multicast hash table */ for(i = 0; i < 8; i++) WRITE_REG(NIC_MAR0 + 2*i, 0); priv->next_pkt = priv->rx_page_start+1; /* init our s/w variable */ WRITE_REG(NIC_CURR, priv->next_pkt); /* set the next buf for current */ /* goto page 0, start NIC */ WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_START); /* take interface out of loopback */ WRITE_REG(NIC_TCR, 0); dev->tbusy = 0; dev->interrupt = 0; dev->start = 1; if(request_irq(IRQ_AMIGA_PORTS, hydra_interrupt, 0, "Hydra Ethernet", dev)) return(-EAGAIN); MOD_INC_USE_COUNT; return(0);}static int hydra_close(struct device *dev){ struct hydra_private *priv = (struct hydra_private *)dev->priv; volatile u8 *nicbase = priv->hydra_nic_base; int n = 5000; dev->start = 0; dev->tbusy = 1;#ifdef HYDRA_DEBUG printk("%s: Shutting down ethercard\n", dev->name); printk("%s: %d packets missed\n", dev->name, priv->stats.rx_missed_errors);#endif WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_STOP); /* wait for NIC to stop (what a nice timeout..) */ while(((READ_REG(NIC_ISR) & ISR_RST) == 0) && --n); free_irq(IRQ_AMIGA_PORTS, dev); MOD_DEC_USE_COUNT; return(0);}static void hydra_interrupt(int irq, void *data, struct pt_regs *fp){ volatile u8 *nicbase; struct device *dev = (struct device *) data; struct hydra_private *priv; u16 intbits; if(dev == NULL) { printk("hydra_interrupt(): irq for unknown device\n"); return; } /* this is not likely a problem - i think */ if(dev->interrupt) printk("%s: re-entering the interrupt handler\n", dev->name); dev->interrupt = 1; priv = (struct hydra_private *) dev->priv; nicbase = (u8 *) priv->hydra_nic_base; /* select page 0 */ WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA); intbits = READ_REG(NIC_ISR) & NIC_INTS; if(intbits == 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -