11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*	ni5010.c: A network driver for the MiCom-Interlan NI5010 ethercard.
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
35b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr *	Copyright 1996,1997,2006 Jan-Pascal van Best and Andreas Mohr.
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	This software may be used and distributed according to the terms
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	of the GNU General Public License, incorporated herein by reference.
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 	The authors may be reached as:
95b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr *		janpascal@vanbest.org		andi@lisas.de
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Sources:
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 	 	Donald Becker's "skeleton.c"
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  		Crynwr ni5010 packet driver
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Changes:
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		v0.0: First test version
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		v0.1: First working version
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		v0.2:
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		v0.3->v0.90: Now demand setting io and irq when loading as module
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	970430	v0.91: modified for Linux 2.1.14
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		v0.92: Implemented Andreas' (better) NI5010 probe
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	970503	v0.93: Fixed auto-irq failure on warm reboot (JB)
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	970623	v1.00: First kernel version (AM)
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	970814	v1.01: Added detection of onboard receive buffer size (AM)
255b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr *	060611	v1.02: slight cleanup: email addresses, driver modernization.
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Bugs:
275b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr *		- not SMP-safe (no locking of I/O accesses)
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		- Note that you have to patch ifconfig for the new /proc/net/dev
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		format. It gives incorrect stats otherwise.
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	To do:
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		Fix all bugs :-)
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		Move some stuff to chipset_init()
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		Handle xmt errors other than collisions
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		Complete merge with Andreas' driver
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		Implement ring buffers (Is this useful? You can't squeeze
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *			too many packet in a 2k buffer!)
385b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr *		Implement DMA (Again, is this useful? Some docs say DMA is
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *			slower than programmed I/O)
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Compile with:
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		gcc -O2 -fomit-frame-pointer -m486 -D__KERNEL__ \
436aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik *			-DMODULE -c ni5010.c
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Insert with e.g.:
465b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr *		insmod ni5010.ko io=0x300 irq=5
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h>
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/dma.h>
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h>
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h>
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h>
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "ni5010.h"
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
675b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohrstatic const char boardname[] = "NI5010";
685b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohrstatic char version[] __initdata =
695b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr	"ni5010.c: v1.02 20060611 Jan-Pascal van Best and Andreas Mohr\n";
706aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* bufsize_rcv == 0 means autoprobing */
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int bufsize_rcv;
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
745b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr#define JUMPERED_INTERRUPTS	/* IRQ line jumpered on board */
755b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr#undef JUMPERED_DMA		/* No DMA used */
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef FULL_IODETECT		/* Only detect in portlist */
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef FULL_IODETECT
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* A zero-terminated list of I/O addresses to be probed. */
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int ports[] __initdata =
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0 };
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Use 0 for production, 1 for verification, >2 for debug */
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef NI5010_DEBUG
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NI5010_DEBUG 0
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Information that needs to be kept for each board. */
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct ni5010_local {
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int o_pkt_size;
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t lock;
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Index to functions, as function prototypes. */
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int	ni5010_probe1(struct net_device *dev, int ioaddr);
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int	ni5010_open(struct net_device *dev);
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int	ni5010_send_packet(struct sk_buff *skb, struct net_device *dev);
1007d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t ni5010_interrupt(int irq, void *dev_id);
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void	ni5010_rx(struct net_device *dev);
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void	ni5010_timeout(struct net_device *dev);
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int	ni5010_close(struct net_device *dev);
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 	ni5010_set_multicast_list(struct net_device *dev);
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void	reset_receiver(struct net_device *dev);
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int	process_xmt_interrupt(struct net_device *dev);
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define tx_done(dev) 1
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void	hardware_send_packet(struct net_device *dev, char *buf, int length, int pad);
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 	chipset_init(struct net_device *dev, int startp);
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void	dump_packet(void *buf, int len);
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 	ni5010_show_registers(struct net_device *dev);
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int io;
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int irq;
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct net_device * __init ni5010_probe(int unit)
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev = alloc_etherdev(sizeof(struct ni5010_local));
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int *port;
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev)
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ERR_PTR(-ENOMEM);
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unit >= 0) {
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sprintf(dev->name, "eth%d", unit);
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netdev_boot_setup_check(dev);
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		io = dev->base_addr;
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irq = dev->irq;
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK2((KERN_DEBUG "%s: Entering ni5010_probe\n", dev->name));
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (io > 0x1ff)	{	/* Check a single specified location. */
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = ni5010_probe1(dev, io);
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (io != 0) {	/* Don't probe at all. */
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -ENXIO;
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef FULL_IODETECT
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (io=0x200; io<0x400 && ni5010_probe1(dev, io) ; io+=0x20)
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			;
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (io == 0x400)
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -ENODEV;
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (port = ports; *port && ni5010_probe1(dev, *port); port++)
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			;
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!*port)
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -ENODEV;
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif	/* FULL_IODETECT */
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = register_netdev(dev);
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out1;
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return dev;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout1:
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_region(dev->base_addr, NI5010_IO_EXTENT);
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_netdev(dev);
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ERR_PTR(err);
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int rd_port(int ioaddr)
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inb(IE_RBUF);
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return inb(IE_SAPROM);
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __init trigger_irq(int ioaddr)
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(0x00, EDLC_RESET);	/* Clear EDLC hold RESET state */
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(0x00, IE_RESET);	/* Board reset */
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(0x00, EDLC_XMASK);	/* Disable all Xmt interrupts */
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(0x00, EDLC_RMASK); /* Disable all Rcv interrupt */
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(0xff, EDLC_XCLR);	/* Clear all pending Xmt interrupts */
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(0xff, EDLC_RCLR);	/* Clear all pending Rcv interrupts */
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Transmit packet mode: Ignore parity, Power xcvr,
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * 	Enable loopback
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(XMD_IG_PAR | XMD_T_MODE | XMD_LBC, EDLC_XMODE);
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(RMD_BROADCAST, EDLC_RMODE); /* Receive normal&broadcast */
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(XM_ALL, EDLC_XMASK);	/* Enable all Xmt interrupts */
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		udelay(50);			/* FIXME: Necessary? */
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(MM_EN_XMT|MM_MUX, IE_MMODE); /* Start transmission */
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19179f1bc06dbb05f222756d6df4a9ff95588c9cc06Alexander Beregalovstatic const struct net_device_ops ni5010_netdev_ops = {
19279f1bc06dbb05f222756d6df4a9ff95588c9cc06Alexander Beregalov	.ndo_open		= ni5010_open,
19379f1bc06dbb05f222756d6df4a9ff95588c9cc06Alexander Beregalov	.ndo_stop		= ni5010_close,
19479f1bc06dbb05f222756d6df4a9ff95588c9cc06Alexander Beregalov	.ndo_start_xmit		= ni5010_send_packet,
195afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko	.ndo_set_rx_mode	= ni5010_set_multicast_list,
19679f1bc06dbb05f222756d6df4a9ff95588c9cc06Alexander Beregalov	.ndo_tx_timeout		= ni5010_timeout,
19779f1bc06dbb05f222756d6df4a9ff95588c9cc06Alexander Beregalov	.ndo_validate_addr	= eth_validate_addr,
19879f1bc06dbb05f222756d6df4a9ff95588c9cc06Alexander Beregalov	.ndo_set_mac_address	= eth_mac_addr,
19979f1bc06dbb05f222756d6df4a9ff95588c9cc06Alexander Beregalov	.ndo_change_mtu		= eth_change_mtu,
20079f1bc06dbb05f222756d6df4a9ff95588c9cc06Alexander Beregalov};
20179f1bc06dbb05f222756d6df4a9ff95588c9cc06Alexander Beregalov
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      This is the real probe routine.  Linux has a history of friendly device
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      probes on the ISA bus.  A good device probes avoids doing writes, and
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      verifies that the correct device exists and functions.
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init ni5010_probe1(struct net_device *dev, int ioaddr)
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static unsigned version_printed;
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ni5010_local *lp;
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int data = 0;
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int boguscount = 40;
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = -ENODEV;
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->base_addr = ioaddr;
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->irq = irq;
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!request_region(ioaddr, NI5010_IO_EXTENT, boardname))
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EBUSY;
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * This is no "official" probe method, I've rather tested which
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * probe works best with my seven NI5010 cards
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * (they have very different serial numbers)
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Suggestions or failure reports are very, very welcome !
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * But I think it is a relatively good probe method
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * since it doesn't use any "outb"
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * It should be nearly 100% reliable !
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * well-known WARNING: this probe method (like many others)
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * will hang the system if a NE2000 card region is probed !
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *   - Andreas
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2376aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 	PRINTK2((KERN_DEBUG "%s: entering ni5010_probe1(%#3x)\n",
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 		dev->name, ioaddr));
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (inb(ioaddr+0) == 0xff)
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ( (rd_port(ioaddr) & rd_port(ioaddr) & rd_port(ioaddr) &
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 rd_port(ioaddr) & rd_port(ioaddr) & rd_port(ioaddr)) != 0xff)
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (boguscount-- == 0)
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK2((KERN_DEBUG "%s: I/O #1 passed!\n", dev->name));
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i=0; i<32; i++)
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ( (data = rd_port(ioaddr)) != 0xff) break;
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (data==0xff)
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK2((KERN_DEBUG "%s: I/O #2 passed!\n", dev->name));
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((data != SA_ADDR0) || (rd_port(ioaddr) != SA_ADDR1) ||
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (rd_port(ioaddr) != SA_ADDR2))
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i=0; i<4; i++)
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rd_port(ioaddr);
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ( (rd_port(ioaddr) != NI5010_MAGICVAL1) ||
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     (rd_port(ioaddr) != NI5010_MAGICVAL2) )
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK2((KERN_DEBUG "%s: I/O #3 passed!\n", dev->name));
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (NI5010_DEBUG && version_printed++ == 0)
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_INFO "%s", version);
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("NI5010 ethercard probe at 0x%x: ", ioaddr);
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->base_addr = ioaddr;
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i=0; i<6; i++) {
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outw(i, IE_GP);
2810795af5729b18218767fab27c44b1384f72dc9adJoe Perches		dev->dev_addr[i] = inb(IE_SAPROM);
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
283e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg	printk("%pM ", dev->dev_addr);
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK2((KERN_DEBUG "%s: I/O #4 passed!\n", dev->name));
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2875b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr#ifdef JUMPERED_INTERRUPTS
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->irq == 0xff)
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		;
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (dev->irq < 2) {
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned long irq_mask;
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		PRINTK2((KERN_DEBUG "%s: I/O #5 passed!\n", dev->name));
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irq_mask = probe_irq_on();
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		trigger_irq(ioaddr);
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mdelay(20);
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->irq = probe_irq_off(irq_mask);
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		PRINTK2((KERN_DEBUG "%s: I/O #6 passed!\n", dev->name));
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (dev->irq == 0) {
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -EAGAIN;
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_WARNING "%s: no IRQ found!\n", dev->name);
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		PRINTK2((KERN_DEBUG "%s: I/O #7 passed!\n", dev->name));
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (dev->irq == 2) {
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->irq = 9;
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3115b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr#endif	/* JUMPERED_INTERRUPTS */
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK2((KERN_DEBUG "%s: I/O #9 passed!\n", dev->name));
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* DMA is not supported (yet?), so no use detecting it */
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp = netdev_priv(dev);
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_init(&lp->lock);
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK2((KERN_DEBUG "%s: I/O #10 passed!\n", dev->name));
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* get the size of the onboard receive buffer
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * higher addresses than bufsize are wrapped into real buffer
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * i.e. data for offs. 0x801 is written to 0x1 with a 2K onboard buffer
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!bufsize_rcv) {
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        	outb(1, IE_MMODE);      /* Put Rcv buffer on system bus */
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        	outw(0, IE_GP);		/* Point GP at start of packet */
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        	outb(0, IE_RBUF);	/* set buffer byte 0 to 0 */
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        	for (i = 1; i < 0xff; i++) {
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                	outw(i << 8, IE_GP); /* Point GP at packet size to be tested */
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                	outb(i, IE_RBUF);
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                	outw(0x0, IE_GP); /* Point GP at start of packet */
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                	data = inb(IE_RBUF);
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                	if (data == i) break;
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        	}
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bufsize_rcv = i << 8;
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        	outw(0, IE_GP);		/* Point GP at start of packet */
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        	outb(0, IE_RBUF);	/* set buffer byte 0 to 0 again */
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3405b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr        printk("-> bufsize rcv/xmt=%d/%d\n", bufsize_rcv, NI5010_BUFSIZE);
3416aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
34279f1bc06dbb05f222756d6df4a9ff95588c9cc06Alexander Beregalov	dev->netdev_ops		= &ni5010_netdev_ops;
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->watchdog_timeo	= HZ/20;
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->flags &= ~IFF_MULTICAST;	/* Multicast doesn't work */
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Shut up the ni5010 */
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0, EDLC_RMASK);	/* Mask all receive interrupts */
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0, EDLC_XMASK);	/* Mask all xmit interrupts */
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0xff, EDLC_RCLR);	/* Kill all pending rcv interrupts */
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0xff, EDLC_XCLR); 	/* Kill all pending xmt interrupts */
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO "%s: NI5010 found at 0x%x, using IRQ %d", dev->name, ioaddr, dev->irq);
3545b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr	if (dev->dma)
3555b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr		printk(" & DMA %d", dev->dma);
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(".\n");
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_region(dev->base_addr, NI5010_IO_EXTENT);
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3636aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik/*
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Open/initialize the board.  This is called (in the current kernel)
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sometime after booting when the 'ifconfig' program is run.
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine should set everything up anew at each open, even
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * registers that "should" only need to be set once at boot, so that
3695b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr * there is a non-reboot way to recover if something goes wrong.
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3716aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ni5010_open(struct net_device *dev)
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ioaddr = dev->base_addr;
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3776aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	PRINTK2((KERN_DEBUG "%s: entering ni5010_open()\n", dev->name));
3786aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
379a0607fd3a25ba1848a63a0d925e36d914735ab47Joe Perches	if (request_irq(dev->irq, ni5010_interrupt, 0, boardname, dev)) {
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "%s: Cannot get irq %#2x\n", dev->name, dev->irq);
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EAGAIN;
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK3((KERN_DEBUG "%s: passed open() #1\n", dev->name));
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        /*
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds         * Always allocate the DMA channel after the IRQ,
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds         * and clean up on failure.
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds         */
3885b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr#ifdef JUMPERED_DMA
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if (request_dma(dev->dma, cardname)) {
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "%s: Cannot get dma %#2x\n", dev->name, dev->dma);
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                free_irq(dev->irq, NULL);
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                return -EAGAIN;
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        }
3945b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr#endif	/* JUMPERED_DMA */
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK3((KERN_DEBUG "%s: passed open() #2\n", dev->name));
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Reset the hardware here.  Don't forget to set the station address. */
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(RS_RESET, EDLC_RESET);	/* Hold up EDLC_RESET while configing board */
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0, IE_RESET);		/* Hardware reset of ni5010 board */
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(XMD_LBC, EDLC_XMODE);	/* Only loopback xmits */
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK3((KERN_DEBUG "%s: passed open() #3\n", dev->name));
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set the station address */
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for(i = 0;i < 6; i++) {
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(dev->dev_addr[i], EDLC_ADDR + i);
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4086aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
4096aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	PRINTK3((KERN_DEBUG "%s: Initialising ni5010\n", dev->name));
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0, EDLC_XMASK);	/* No xmit interrupts for now */
4116aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	outb(XMD_IG_PAR | XMD_T_MODE | XMD_LBC, EDLC_XMODE);
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* Normal packet xmit mode */
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0xff, EDLC_XCLR);	/* Clear all pending xmit interrupts */
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(RMD_BROADCAST, EDLC_RMODE);
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* Receive broadcast and normal packets */
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reset_receiver(dev);	/* Ready ni5010 for receiving packets */
4176aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0, EDLC_RESET);	/* Un-reset the ni5010 */
4196aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_start_queue(dev);
4216aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
4226aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	if (NI5010_DEBUG) ni5010_show_registers(dev);
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK((KERN_DEBUG "%s: open successful\n", dev->name));
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     	return 0;
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void reset_receiver(struct net_device *dev)
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ioaddr = dev->base_addr;
4316aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK3((KERN_DEBUG "%s: resetting receiver\n", dev->name));
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(0, IE_GP);		/* Receive packet at start of buffer */
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0xff, EDLC_RCLR);	/* Clear all pending rcv interrupts */
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0, IE_MMODE);	/* Put EDLC to rcv buffer */
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(MM_EN_RCV, IE_MMODE); /* Enable rcv */
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0xff, EDLC_RMASK);	/* Enable all rcv interrupts */
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ni5010_timeout(struct net_device *dev)
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   tx_done(dev) ? "IRQ conflict" : "network cable problem");
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Try to restart the adaptor. */
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME: Give it a real kick here */
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	chipset_init(dev, 1);
4471ae5dc342ac78d7a42965fd1f323815f6f5ef2c1Eric Dumazet	dev->trans_start = jiffies; /* prevent tx timeout */
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_wake_queue(dev);
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ni5010_send_packet(struct sk_buff *skb, struct net_device *dev)
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK2((KERN_DEBUG "%s: entering ni5010_send_packet\n", dev->name));
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4576aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	/*
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds         * Block sending
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4606aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_stop_queue(dev);
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hardware_send_packet(dev, (unsigned char *)skb->data, skb->len, length-skb->len);
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_kfree_skb (skb);
4646ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy	return NETDEV_TX_OK;
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4676aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik/*
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The typical workload of the driver:
4696aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik * Handle the network interface interrupts.
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4717d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t ni5010_interrupt(int irq, void *dev_id)
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev = dev_id;
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ni5010_local *lp;
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ioaddr, status;
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int xmit_was_error = 0;
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK2((KERN_DEBUG "%s: entering ni5010_interrupt\n", dev->name));
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ioaddr = dev->base_addr;
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp = netdev_priv(dev);
4826aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock(&lp->lock);
4846aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	status = inb(IE_ISTAT);
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK3((KERN_DEBUG "%s: IE_ISTAT = %#02x\n", dev->name, status));
4866aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if ((status & IS_R_INT) == 0) ni5010_rx(dev);
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if ((status & IS_X_INT) == 0) {
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                xmit_was_error = process_xmt_interrupt(dev);
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        }
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if ((status & IS_DMA_INT) == 0) {
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                PRINTK((KERN_DEBUG "%s: DMA complete (?)\n", dev->name));
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                outb(0, IE_DMA_RST); /* Reset DMA int */
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        }
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4986aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	if (!xmit_was_error)
4996aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		reset_receiver(dev);
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock(&lp->lock);
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IRQ_HANDLED;
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dump_packet(void *buf, int len)
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
5086aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_DEBUG "Packet length = %#4x\n", len);
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < len; i++){
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (i % 16 == 0) printk(KERN_DEBUG "%#4.4x", i);
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (i % 2 == 0) printk(" ");
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("%2.2x", ((unsigned char *)buf)[i]);
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (i % 16 == 15) printk("\n");
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("\n");
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* We have a good packet, get it out of the buffer. */
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ni5010_rx(struct net_device *dev)
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ioaddr = dev->base_addr;
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char rcv_stat;
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i_pkt_size;
5266aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
5276aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	PRINTK2((KERN_DEBUG "%s: entering ni5010_rx()\n", dev->name));
5286aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rcv_stat = inb(EDLC_RSTAT);
5306aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	PRINTK3((KERN_DEBUG "%s: EDLC_RSTAT = %#2x\n", dev->name, rcv_stat));
5316aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ( (rcv_stat & RS_VALID_BITS) != RS_PKT_OK) {
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		PRINTK((KERN_INFO "%s: receive error.\n", dev->name));
53409f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik		dev->stats.rx_errors++;
53509f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik		if (rcv_stat & RS_RUNT) dev->stats.rx_length_errors++;
53609f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik		if (rcv_stat & RS_ALIGN) dev->stats.rx_frame_errors++;
53709f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik		if (rcv_stat & RS_CRC_ERR) dev->stats.rx_crc_errors++;
53809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik		if (rcv_stat & RS_OFLW) dev->stats.rx_fifo_errors++;
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        	outb(0xff, EDLC_RCLR); /* Clear the interrupt */
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5426aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        outb(0xff, EDLC_RCLR);  /* Clear the interrupt */
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i_pkt_size = inw(IE_RCNT);
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (i_pkt_size > ETH_FRAME_LEN || i_pkt_size < 10 ) {
5476aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		PRINTK((KERN_DEBUG "%s: Packet size error, packet size = %#4.4x\n",
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->name, i_pkt_size));
54909f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik		dev->stats.rx_errors++;
55009f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik		dev->stats.rx_length_errors++;
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Malloc up new buffer. */
555dae2e9f430c46c29e3f771110094bd3da3625aa4Pradeep A. Dalvi	skb = netdev_alloc_skb(dev, i_pkt_size + 3);
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (skb == NULL) {
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
55809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik		dev->stats.rx_dropped++;
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5616aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_reserve(skb, 2);
5636aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Read packet into buffer */
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        outb(MM_MUX, IE_MMODE); /* Rcv buffer to system bus */
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(0, IE_GP);	/* Seek to beginning of packet */
5676aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	insb(IE_RBUF, skb_put(skb, i_pkt_size), i_pkt_size);
5686aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
5696aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	if (NI5010_DEBUG >= 4)
5706aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		dump_packet(skb->data, skb->len);
5716aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb->protocol = eth_type_trans(skb,dev);
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_rx(skb);
57409f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik	dev->stats.rx_packets++;
57509f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik	dev->stats.rx_bytes += i_pkt_size;
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5776aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	PRINTK2((KERN_DEBUG "%s: Received packet, size=%#4.4x\n",
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->name, i_pkt_size));
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int process_xmt_interrupt(struct net_device *dev)
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ni5010_local *lp = netdev_priv(dev);
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ioaddr = dev->base_addr;
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int xmit_stat;
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK2((KERN_DEBUG "%s: entering process_xmt_interrupt\n", dev->name));
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xmit_stat = inb(EDLC_XSTAT);
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK3((KERN_DEBUG "%s: EDLC_XSTAT = %2.2x\n", dev->name, xmit_stat));
5916aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0, EDLC_XMASK);	/* Disable xmit IRQ's */
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0xff, EDLC_XCLR);	/* Clear all pending xmit IRQ's */
5946aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (xmit_stat & XS_COLL){
5966aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		PRINTK((KERN_DEBUG "%s: collision detected, retransmitting\n",
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->name));
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outw(NI5010_BUFSIZE - lp->o_pkt_size, IE_GP);
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* outb(0, IE_MMODE); */ /* xmt buf on sysbus FIXME: needed ? */
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(MM_EN_XMT | MM_MUX, IE_MMODE);
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(XM_ALL, EDLC_XMASK); /* Enable xmt IRQ's */
60209f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik		dev->stats.collisions++;
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME: handle other xmt error conditions */
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
60809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik	dev->stats.tx_packets++;
60909f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik	dev->stats.tx_bytes += lp->o_pkt_size;
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_wake_queue(dev);
6116aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
6126aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	PRINTK2((KERN_DEBUG "%s: sent packet, size=%#4.4x\n",
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->name, lp->o_pkt_size));
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The inverse routine to ni5010_open(). */
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ni5010_close(struct net_device *dev)
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ioaddr = dev->base_addr;
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK2((KERN_DEBUG "%s: entering ni5010_close\n", dev->name));
6245b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr#ifdef JUMPERED_INTERRUPTS
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_irq(dev->irq, NULL);
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Put card in held-RESET state */
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0, IE_MMODE);
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(RS_RESET, EDLC_RESET);
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_stop_queue(dev);
6326aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK((KERN_DEBUG "%s: %s closed down\n", dev->name, boardname));
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Set or clear the multicast filter for this adaptor.
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   num_addrs == -1      Promiscuous mode, receive all packets
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   num_addrs == 0       Normal mode, clear multicast list
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   num_addrs > 0        Multicast mode, receive normal and MC packets, and do
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        best-effort filtering.
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ni5010_set_multicast_list(struct net_device *dev)
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6466aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	short ioaddr = dev->base_addr;
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK2((KERN_DEBUG "%s: entering set_multicast_list\n", dev->name));
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
650f9dcbcc9e338d08c0f7de7eba4eaafbbb7f81249Jiri Pirko	if (dev->flags & IFF_PROMISC || dev->flags & IFF_ALLMULTI ||
651f9dcbcc9e338d08c0f7de7eba4eaafbbb7f81249Jiri Pirko	    !netdev_mc_empty(dev)) {
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(RMD_PROMISC, EDLC_RMODE); /* Enable promiscuous mode */
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		PRINTK((KERN_DEBUG "%s: Entering promiscuous mode\n", dev->name));
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		PRINTK((KERN_DEBUG "%s: Entering broadcast mode\n", dev->name));
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(RMD_BROADCAST, EDLC_RMODE);  /* Disable promiscuous mode, use normal mode */
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hardware_send_packet(struct net_device *dev, char *buf, int length, int pad)
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ni5010_local *lp = netdev_priv(dev);
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ioaddr = dev->base_addr;
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int buf_offs;
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK2((KERN_DEBUG "%s: entering hardware_send_packet\n", dev->name));
6686aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if (length > ETH_FRAME_LEN) {
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                PRINTK((KERN_WARNING "%s: packet too large, not possible\n",
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        dev->name));
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                return;
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        }
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (NI5010_DEBUG) ni5010_show_registers(dev);
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (inb(IE_ISTAT) & IS_EN_XMT) {
6786aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		PRINTK((KERN_WARNING "%s: sending packet while already transmitting, not possible\n",
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->name));
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6826aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (NI5010_DEBUG > 3) dump_packet(buf, length);
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf_offs = NI5010_BUFSIZE - length - pad;
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&lp->lock, flags);
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->o_pkt_size = length + pad;
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0, EDLC_RMASK);	/* Mask all receive interrupts */
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0, IE_MMODE);	/* Put Xmit buffer on system bus */
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0xff, EDLC_RCLR);	/* Clear out pending rcv interrupts */
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(buf_offs, IE_GP); /* Point GP at start of packet */
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outsb(IE_XBUF, buf, length); /* Put data in buffer */
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while(pad--)
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(0, IE_XBUF);
6986aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(buf_offs, IE_GP); /* Rewrite where packet starts */
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* should work without that outb() (Crynwr used it) */
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*outb(MM_MUX, IE_MMODE);*/ /* Xmt buffer to EDLC bus */
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(MM_EN_XMT | MM_MUX, IE_MMODE); /* Begin transmission */
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(XM_ALL, EDLC_XMASK); /* Cause interrupt after completion or fail */
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&lp->lock, flags);
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_wake_queue(dev);
7096aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
7106aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	if (NI5010_DEBUG) ni5010_show_registers(dev);
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void chipset_init(struct net_device *dev, int startp)
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME: Move some stuff here */
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK3((KERN_DEBUG "%s: doing NOTHING in chipset_init\n", dev->name));
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ni5010_show_registers(struct net_device *dev)
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ioaddr = dev->base_addr;
7226aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK3((KERN_DEBUG "%s: XSTAT %#2.2x\n", dev->name, inb(EDLC_XSTAT)));
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK3((KERN_DEBUG "%s: XMASK %#2.2x\n", dev->name, inb(EDLC_XMASK)));
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK3((KERN_DEBUG "%s: RSTAT %#2.2x\n", dev->name, inb(EDLC_RSTAT)));
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK3((KERN_DEBUG "%s: RMASK %#2.2x\n", dev->name, inb(EDLC_RMASK)));
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK3((KERN_DEBUG "%s: RMODE %#2.2x\n", dev->name, inb(EDLC_RMODE)));
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK3((KERN_DEBUG "%s: XMODE %#2.2x\n", dev->name, inb(EDLC_XMODE)));
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK3((KERN_DEBUG "%s: ISTAT %#2.2x\n", dev->name, inb(IE_ISTAT)));
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef MODULE
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct net_device *dev_ni5010;
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7358d3b33f67fdc0fb364a1ef6d8fbbea7c2e4e6c98Rusty Russellmodule_param(io, int, 0);
7368d3b33f67fdc0fb364a1ef6d8fbbea7c2e4e6c98Rusty Russellmodule_param(irq, int, 0);
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(io, "ni5010 I/O base address");
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(irq, "ni5010 IRQ number");
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7405b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohrstatic int __init ni5010_init_module(void)
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK2((KERN_DEBUG "%s: entering init_module\n", boardname));
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(io <= 0 || irq == 0){
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   	printk(KERN_WARNING "%s: Autoprobing not allowed for modules.\n", boardname);
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "%s: Set symbols 'io' and 'irq'\n", boardname);
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   	return -EINVAL;
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*/
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (io <= 0){
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "%s: Autoprobing for modules is hazardous, trying anyway..\n", boardname);
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK2((KERN_DEBUG "%s: init_module irq=%#2x, io=%#3x\n", boardname, irq, io));
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_ni5010 = ni5010_probe(-1);
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (IS_ERR(dev_ni5010))
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return PTR_ERR(dev_ni5010);
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        return 0;
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7615b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohrstatic void __exit ni5010_cleanup_module(void)
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRINTK2((KERN_DEBUG "%s: entering cleanup_module\n", boardname));
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unregister_netdev(dev_ni5010);
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_region(dev_ni5010->base_addr, NI5010_IO_EXTENT);
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_netdev(dev_ni5010);
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7685b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohrmodule_init(ni5010_init_module);
7695b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohrmodule_exit(ni5010_cleanup_module);
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* MODULE */
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
772