xref: /openbmc/linux/drivers/net/ethernet/8390/ne.c (revision da9da01d)
1644570b8SJeff Kirsher /* ne.c: A general non-shared-memory NS8390 ethernet driver for linux. */
2644570b8SJeff Kirsher /*
3644570b8SJeff Kirsher     Written 1992-94 by Donald Becker.
4644570b8SJeff Kirsher 
5644570b8SJeff Kirsher     Copyright 1993 United States Government as represented by the
6644570b8SJeff Kirsher     Director, National Security Agency.
7644570b8SJeff Kirsher 
8644570b8SJeff Kirsher     This software may be used and distributed according to the terms
9644570b8SJeff Kirsher     of the GNU General Public License, incorporated herein by reference.
10644570b8SJeff Kirsher 
11644570b8SJeff Kirsher     The author may be reached as becker@scyld.com, or C/O
12644570b8SJeff Kirsher     Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403
13644570b8SJeff Kirsher 
14644570b8SJeff Kirsher     This driver should work with many programmed-I/O 8390-based ethernet
15644570b8SJeff Kirsher     boards.  Currently it supports the NE1000, NE2000, many clones,
16644570b8SJeff Kirsher     and some Cabletron products.
17644570b8SJeff Kirsher 
18644570b8SJeff Kirsher     Changelog:
19644570b8SJeff Kirsher 
20644570b8SJeff Kirsher     Paul Gortmaker	: use ENISR_RDC to monitor Tx PIO uploads, made
21644570b8SJeff Kirsher 			  sanity checks and bad clone support optional.
22644570b8SJeff Kirsher     Paul Gortmaker	: new reset code, reset card after probe at boot.
23644570b8SJeff Kirsher     Paul Gortmaker	: multiple card support for module users.
24644570b8SJeff Kirsher     Paul Gortmaker	: Support for PCI ne2k clones, similar to lance.c
25644570b8SJeff Kirsher     Paul Gortmaker	: Allow users with bad cards to avoid full probe.
26644570b8SJeff Kirsher     Paul Gortmaker	: PCI probe changes, more PCI cards supported.
27644570b8SJeff Kirsher     rjohnson@analogic.com : Changed init order so an interrupt will only
28644570b8SJeff Kirsher     occur after memory is allocated for dev->priv. Deallocated memory
29644570b8SJeff Kirsher     last in cleanup_modue()
30644570b8SJeff Kirsher     Richard Guenther    : Added support for ISAPnP cards
31644570b8SJeff Kirsher     Paul Gortmaker	: Discontinued PCI support - use ne2k-pci.c instead.
32644570b8SJeff Kirsher     Hayato Fujiwara	: Add m32r support.
33644570b8SJeff Kirsher 
34644570b8SJeff Kirsher */
35644570b8SJeff Kirsher 
36644570b8SJeff Kirsher /* Routines for the NatSemi-based designs (NE[12]000). */
37644570b8SJeff Kirsher 
38644570b8SJeff Kirsher static const char version1[] =
39644570b8SJeff Kirsher "ne.c:v1.10 9/23/94 Donald Becker (becker@scyld.com)\n";
40644570b8SJeff Kirsher static const char version2[] =
41644570b8SJeff Kirsher "Last modified Nov 1, 2000 by Paul Gortmaker\n";
42644570b8SJeff Kirsher 
43644570b8SJeff Kirsher 
44644570b8SJeff Kirsher #include <linux/module.h>
45644570b8SJeff Kirsher #include <linux/kernel.h>
46644570b8SJeff Kirsher #include <linux/errno.h>
47644570b8SJeff Kirsher #include <linux/isapnp.h>
48644570b8SJeff Kirsher #include <linux/init.h>
49644570b8SJeff Kirsher #include <linux/interrupt.h>
50644570b8SJeff Kirsher #include <linux/delay.h>
51644570b8SJeff Kirsher #include <linux/netdevice.h>
52644570b8SJeff Kirsher #include <linux/etherdevice.h>
53644570b8SJeff Kirsher #include <linux/jiffies.h>
54644570b8SJeff Kirsher #include <linux/platform_device.h>
55644570b8SJeff Kirsher 
56644570b8SJeff Kirsher #include <asm/io.h>
57644570b8SJeff Kirsher 
58644570b8SJeff Kirsher #include "8390.h"
59644570b8SJeff Kirsher 
60644570b8SJeff Kirsher #define DRV_NAME "ne"
61644570b8SJeff Kirsher 
62644570b8SJeff Kirsher /* Some defines that people can play with if so inclined. */
63644570b8SJeff Kirsher 
64644570b8SJeff Kirsher /* Do we support clones that don't adhere to 14,15 of the SAprom ? */
65644570b8SJeff Kirsher #define SUPPORT_NE_BAD_CLONES
66644570b8SJeff Kirsher /* 0xbad = bad sig or no reset ack */
67644570b8SJeff Kirsher #define BAD 0xbad
68644570b8SJeff Kirsher 
69644570b8SJeff Kirsher #define MAX_NE_CARDS	4	/* Max number of NE cards per module */
70644570b8SJeff Kirsher static struct platform_device *pdev_ne[MAX_NE_CARDS];
71644570b8SJeff Kirsher static int io[MAX_NE_CARDS];
72644570b8SJeff Kirsher static int irq[MAX_NE_CARDS];
73644570b8SJeff Kirsher static int bad[MAX_NE_CARDS];
74644570b8SJeff Kirsher 
75644570b8SJeff Kirsher #ifdef MODULE
76644570b8SJeff Kirsher module_param_array(io, int, NULL, 0);
77644570b8SJeff Kirsher module_param_array(irq, int, NULL, 0);
78644570b8SJeff Kirsher module_param_array(bad, int, NULL, 0);
79644570b8SJeff Kirsher MODULE_PARM_DESC(io, "I/O base address(es),required");
80644570b8SJeff Kirsher MODULE_PARM_DESC(irq, "IRQ number(s)");
81644570b8SJeff Kirsher MODULE_PARM_DESC(bad, "Accept card(s) with bad signatures");
82644570b8SJeff Kirsher MODULE_DESCRIPTION("NE1000/NE2000 ISA/PnP Ethernet driver");
83644570b8SJeff Kirsher MODULE_LICENSE("GPL");
84644570b8SJeff Kirsher #endif /* MODULE */
85644570b8SJeff Kirsher 
86644570b8SJeff Kirsher /* Do we perform extra sanity checks on stuff ? */
87644570b8SJeff Kirsher /* #define NE_SANITY_CHECK */
88644570b8SJeff Kirsher 
89644570b8SJeff Kirsher /* Do we implement the read before write bugfix ? */
90644570b8SJeff Kirsher /* #define NE_RW_BUGFIX */
91644570b8SJeff Kirsher 
92644570b8SJeff Kirsher /* Do we have a non std. amount of memory? (in units of 256 byte pages) */
93644570b8SJeff Kirsher /* #define PACKETBUF_MEMSIZE	0x40 */
94644570b8SJeff Kirsher 
95644570b8SJeff Kirsher /* This is set up so that no ISA autoprobe takes place. We can't guarantee
96644570b8SJeff Kirsher that the ne2k probe is the last 8390 based probe to take place (as it
97644570b8SJeff Kirsher is at boot) and so the probe will get confused by any other 8390 cards.
98644570b8SJeff Kirsher ISA device autoprobes on a running machine are not recommended anyway. */
99644570b8SJeff Kirsher #if !defined(MODULE) && (defined(CONFIG_ISA) || defined(CONFIG_M32R))
100644570b8SJeff Kirsher /* Do we need a portlist for the ISA auto-probe ? */
101644570b8SJeff Kirsher #define NEEDS_PORTLIST
102644570b8SJeff Kirsher #endif
103644570b8SJeff Kirsher 
104644570b8SJeff Kirsher /* A zero-terminated list of I/O addresses to be probed at boot. */
105644570b8SJeff Kirsher #ifdef NEEDS_PORTLIST
106644570b8SJeff Kirsher static unsigned int netcard_portlist[] __initdata = {
107644570b8SJeff Kirsher 	0x300, 0x280, 0x320, 0x340, 0x360, 0x380, 0
108644570b8SJeff Kirsher };
109644570b8SJeff Kirsher #endif
110644570b8SJeff Kirsher 
111644570b8SJeff Kirsher static struct isapnp_device_id isapnp_clone_list[] __initdata = {
112644570b8SJeff Kirsher 	{	ISAPNP_CARD_ID('A','X','E',0x2011),
113644570b8SJeff Kirsher 		ISAPNP_VENDOR('A','X','E'), ISAPNP_FUNCTION(0x2011),
114644570b8SJeff Kirsher 		(long) "NetGear EA201" },
115644570b8SJeff Kirsher 	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
116644570b8SJeff Kirsher 		ISAPNP_VENDOR('E','D','I'), ISAPNP_FUNCTION(0x0216),
117644570b8SJeff Kirsher 		(long) "NN NE2000" },
118644570b8SJeff Kirsher 	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
119644570b8SJeff Kirsher 		ISAPNP_VENDOR('P','N','P'), ISAPNP_FUNCTION(0x80d6),
120644570b8SJeff Kirsher 		(long) "Generic PNP" },
121644570b8SJeff Kirsher 	{ }	/* terminate list */
122644570b8SJeff Kirsher };
123644570b8SJeff Kirsher 
124644570b8SJeff Kirsher MODULE_DEVICE_TABLE(isapnp, isapnp_clone_list);
125644570b8SJeff Kirsher 
126644570b8SJeff Kirsher #ifdef SUPPORT_NE_BAD_CLONES
127644570b8SJeff Kirsher /* A list of bad clones that we none-the-less recognize. */
128644570b8SJeff Kirsher static struct { const char *name8, *name16; unsigned char SAprefix[4];}
129644570b8SJeff Kirsher bad_clone_list[] __initdata = {
130644570b8SJeff Kirsher     {"DE100", "DE200", {0x00, 0xDE, 0x01,}},
131644570b8SJeff Kirsher     {"DE120", "DE220", {0x00, 0x80, 0xc8,}},
132644570b8SJeff Kirsher     {"DFI1000", "DFI2000", {'D', 'F', 'I',}}, /* Original, eh?  */
133644570b8SJeff Kirsher     {"EtherNext UTP8", "EtherNext UTP16", {0x00, 0x00, 0x79}},
134644570b8SJeff Kirsher     {"NE1000","NE2000-invalid", {0x00, 0x00, 0xd8}}, /* Ancient real NE1000. */
135644570b8SJeff Kirsher     {"NN1000", "NN2000",  {0x08, 0x03, 0x08}}, /* Outlaw no-name clone. */
136644570b8SJeff Kirsher     {"4-DIM8","4-DIM16", {0x00,0x00,0x4d,}},  /* Outlaw 4-Dimension cards. */
137644570b8SJeff Kirsher     {"Con-Intl_8", "Con-Intl_16", {0x00, 0x00, 0x24}}, /* Connect Int'nl */
138644570b8SJeff Kirsher     {"ET-100","ET-200", {0x00, 0x45, 0x54}}, /* YANG and YA clone */
139644570b8SJeff Kirsher     {"COMPEX","COMPEX16",{0x00,0x80,0x48}}, /* Broken ISA Compex cards */
140644570b8SJeff Kirsher     {"E-LAN100", "E-LAN200", {0x00, 0x00, 0x5d}}, /* Broken ne1000 clones */
141644570b8SJeff Kirsher     {"PCM-4823", "PCM-4823", {0x00, 0xc0, 0x6c}}, /* Broken Advantech MoBo */
142644570b8SJeff Kirsher     {"REALTEK", "RTL8019", {0x00, 0x00, 0xe8}}, /* no-name with Realtek chip */
143644570b8SJeff Kirsher #ifdef CONFIG_MACH_TX49XX
144644570b8SJeff Kirsher     {"RBHMA4X00-RTL8019", "RBHMA4X00-RTL8019", {0x00, 0x60, 0x0a}},  /* Toshiba built-in */
145644570b8SJeff Kirsher #endif
146644570b8SJeff Kirsher     {"LCS-8834", "LCS-8836", {0x04, 0x04, 0x37}}, /* ShinyNet (SET) */
147644570b8SJeff Kirsher     {NULL,}
148644570b8SJeff Kirsher };
149644570b8SJeff Kirsher #endif
150644570b8SJeff Kirsher 
151644570b8SJeff Kirsher /* ---- No user-serviceable parts below ---- */
152644570b8SJeff Kirsher 
153644570b8SJeff Kirsher #define NE_BASE	 (dev->base_addr)
154644570b8SJeff Kirsher #define NE_CMD	 	0x00
155644570b8SJeff Kirsher #define NE_DATAPORT	0x10	/* NatSemi-defined port window offset. */
156644570b8SJeff Kirsher #define NE_RESET	0x1f	/* Issue a read to reset, a write to clear. */
157644570b8SJeff Kirsher #define NE_IO_EXTENT	0x20
158644570b8SJeff Kirsher 
159644570b8SJeff Kirsher #define NE1SM_START_PG	0x20	/* First page of TX buffer */
160644570b8SJeff Kirsher #define NE1SM_STOP_PG 	0x40	/* Last page +1 of RX ring */
161644570b8SJeff Kirsher #define NESM_START_PG	0x40	/* First page of TX buffer */
162644570b8SJeff Kirsher #define NESM_STOP_PG	0x80	/* Last page +1 of RX ring */
163644570b8SJeff Kirsher 
164644570b8SJeff Kirsher #if defined(CONFIG_PLAT_MAPPI)
165644570b8SJeff Kirsher #  define DCR_VAL 0x4b
166644570b8SJeff Kirsher #elif defined(CONFIG_PLAT_OAKS32R)  || \
167644570b8SJeff Kirsher    defined(CONFIG_MACH_TX49XX)
168644570b8SJeff Kirsher #  define DCR_VAL 0x48		/* 8-bit mode */
169644570b8SJeff Kirsher #else
170644570b8SJeff Kirsher #  define DCR_VAL 0x49
171644570b8SJeff Kirsher #endif
172644570b8SJeff Kirsher 
173644570b8SJeff Kirsher static int ne_probe1(struct net_device *dev, unsigned long ioaddr);
174644570b8SJeff Kirsher static int ne_probe_isapnp(struct net_device *dev);
175644570b8SJeff Kirsher 
176644570b8SJeff Kirsher static void ne_reset_8390(struct net_device *dev);
177644570b8SJeff Kirsher static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
178644570b8SJeff Kirsher 			  int ring_page);
179644570b8SJeff Kirsher static void ne_block_input(struct net_device *dev, int count,
180644570b8SJeff Kirsher 			  struct sk_buff *skb, int ring_offset);
181644570b8SJeff Kirsher static void ne_block_output(struct net_device *dev, const int count,
182644570b8SJeff Kirsher 		const unsigned char *buf, const int start_page);
183644570b8SJeff Kirsher 
184644570b8SJeff Kirsher 
185644570b8SJeff Kirsher /*  Probe for various non-shared-memory ethercards.
186644570b8SJeff Kirsher 
187644570b8SJeff Kirsher    NEx000-clone boards have a Station Address PROM (SAPROM) in the packet
188644570b8SJeff Kirsher    buffer memory space.  NE2000 clones have 0x57,0x57 in bytes 0x0e,0x0f of
189644570b8SJeff Kirsher    the SAPROM, while other supposed NE2000 clones must be detected by their
190644570b8SJeff Kirsher    SA prefix.
191644570b8SJeff Kirsher 
192644570b8SJeff Kirsher    Reading the SAPROM from a word-wide card with the 8390 set in byte-wide
193644570b8SJeff Kirsher    mode results in doubled values, which can be detected and compensated for.
194644570b8SJeff Kirsher 
195644570b8SJeff Kirsher    The probe is also responsible for initializing the card and filling
196644570b8SJeff Kirsher    in the 'dev' and 'ei_status' structures.
197644570b8SJeff Kirsher 
198644570b8SJeff Kirsher    We use the minimum memory size for some ethercard product lines, iff we can't
199644570b8SJeff Kirsher    distinguish models.  You can increase the packet buffer size by setting
200644570b8SJeff Kirsher    PACKETBUF_MEMSIZE.  Reported Cabletron packet buffer locations are:
201644570b8SJeff Kirsher 	E1010   starts at 0x100 and ends at 0x2000.
202644570b8SJeff Kirsher 	E1010-x starts at 0x100 and ends at 0x8000. ("-x" means "more memory")
203644570b8SJeff Kirsher 	E2010	 starts at 0x100 and ends at 0x4000.
204644570b8SJeff Kirsher 	E2010-x starts at 0x100 and ends at 0xffff.  */
205644570b8SJeff Kirsher 
206644570b8SJeff Kirsher static int __init do_ne_probe(struct net_device *dev)
207644570b8SJeff Kirsher {
208644570b8SJeff Kirsher 	unsigned long base_addr = dev->base_addr;
209644570b8SJeff Kirsher #ifdef NEEDS_PORTLIST
210644570b8SJeff Kirsher 	int orig_irq = dev->irq;
211644570b8SJeff Kirsher #endif
212644570b8SJeff Kirsher 
213644570b8SJeff Kirsher 	/* First check any supplied i/o locations. User knows best. <cough> */
214644570b8SJeff Kirsher 	if (base_addr > 0x1ff) {	/* Check a single specified location. */
215644570b8SJeff Kirsher 		int ret = ne_probe1(dev, base_addr);
216644570b8SJeff Kirsher 		if (ret)
217644570b8SJeff Kirsher 			printk(KERN_WARNING "ne.c: No NE*000 card found at "
218644570b8SJeff Kirsher 				"i/o = %#lx\n", base_addr);
219644570b8SJeff Kirsher 		return ret;
220644570b8SJeff Kirsher 	}
221644570b8SJeff Kirsher 	else if (base_addr != 0)	/* Don't probe at all. */
222644570b8SJeff Kirsher 		return -ENXIO;
223644570b8SJeff Kirsher 
224644570b8SJeff Kirsher 	/* Then look for any installed ISAPnP clones */
225644570b8SJeff Kirsher 	if (isapnp_present() && (ne_probe_isapnp(dev) == 0))
226644570b8SJeff Kirsher 		return 0;
227644570b8SJeff Kirsher 
228644570b8SJeff Kirsher #ifdef NEEDS_PORTLIST
229644570b8SJeff Kirsher 	/* Last resort. The semi-risky ISA auto-probe. */
230644570b8SJeff Kirsher 	for (base_addr = 0; netcard_portlist[base_addr] != 0; base_addr++) {
231644570b8SJeff Kirsher 		int ioaddr = netcard_portlist[base_addr];
232644570b8SJeff Kirsher 		dev->irq = orig_irq;
233644570b8SJeff Kirsher 		if (ne_probe1(dev, ioaddr) == 0)
234644570b8SJeff Kirsher 			return 0;
235644570b8SJeff Kirsher 	}
236644570b8SJeff Kirsher #endif
237644570b8SJeff Kirsher 
238644570b8SJeff Kirsher 	return -ENODEV;
239644570b8SJeff Kirsher }
240644570b8SJeff Kirsher 
241644570b8SJeff Kirsher static int __init ne_probe_isapnp(struct net_device *dev)
242644570b8SJeff Kirsher {
243644570b8SJeff Kirsher 	int i;
244644570b8SJeff Kirsher 
245644570b8SJeff Kirsher 	for (i = 0; isapnp_clone_list[i].vendor != 0; i++) {
246644570b8SJeff Kirsher 		struct pnp_dev *idev = NULL;
247644570b8SJeff Kirsher 
248644570b8SJeff Kirsher 		while ((idev = pnp_find_dev(NULL,
249644570b8SJeff Kirsher 					    isapnp_clone_list[i].vendor,
250644570b8SJeff Kirsher 					    isapnp_clone_list[i].function,
251644570b8SJeff Kirsher 					    idev))) {
252644570b8SJeff Kirsher 			/* Avoid already found cards from previous calls */
253644570b8SJeff Kirsher 			if (pnp_device_attach(idev) < 0)
254644570b8SJeff Kirsher 				continue;
255644570b8SJeff Kirsher 			if (pnp_activate_dev(idev) < 0) {
256644570b8SJeff Kirsher 			      	pnp_device_detach(idev);
257644570b8SJeff Kirsher 			      	continue;
258644570b8SJeff Kirsher 			}
259644570b8SJeff Kirsher 			/* if no io and irq, search for next */
260644570b8SJeff Kirsher 			if (!pnp_port_valid(idev, 0) || !pnp_irq_valid(idev, 0)) {
261644570b8SJeff Kirsher 				pnp_device_detach(idev);
262644570b8SJeff Kirsher 				continue;
263644570b8SJeff Kirsher 			}
264644570b8SJeff Kirsher 			/* found it */
265644570b8SJeff Kirsher 			dev->base_addr = pnp_port_start(idev, 0);
266644570b8SJeff Kirsher 			dev->irq = pnp_irq(idev, 0);
267644570b8SJeff Kirsher 			printk(KERN_INFO "ne.c: ISAPnP reports %s at i/o %#lx, irq %d.\n",
268644570b8SJeff Kirsher 				(char *) isapnp_clone_list[i].driver_data,
269644570b8SJeff Kirsher 				dev->base_addr, dev->irq);
270644570b8SJeff Kirsher 			if (ne_probe1(dev, dev->base_addr) != 0) {	/* Shouldn't happen. */
271644570b8SJeff Kirsher 				printk(KERN_ERR "ne.c: Probe of ISAPnP card at %#lx failed.\n", dev->base_addr);
272644570b8SJeff Kirsher 				pnp_device_detach(idev);
273644570b8SJeff Kirsher 				return -ENXIO;
274644570b8SJeff Kirsher 			}
275644570b8SJeff Kirsher 			ei_status.priv = (unsigned long)idev;
276644570b8SJeff Kirsher 			break;
277644570b8SJeff Kirsher 		}
278644570b8SJeff Kirsher 		if (!idev)
279644570b8SJeff Kirsher 			continue;
280644570b8SJeff Kirsher 		return 0;
281644570b8SJeff Kirsher 	}
282644570b8SJeff Kirsher 
283644570b8SJeff Kirsher 	return -ENODEV;
284644570b8SJeff Kirsher }
285644570b8SJeff Kirsher 
286644570b8SJeff Kirsher static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr)
287644570b8SJeff Kirsher {
288644570b8SJeff Kirsher 	int i;
289644570b8SJeff Kirsher 	unsigned char SA_prom[32];
290644570b8SJeff Kirsher 	int wordlength = 2;
291644570b8SJeff Kirsher 	const char *name = NULL;
292644570b8SJeff Kirsher 	int start_page, stop_page;
293644570b8SJeff Kirsher 	int neX000, ctron, copam, bad_card;
294644570b8SJeff Kirsher 	int reg0, ret;
295644570b8SJeff Kirsher 	static unsigned version_printed;
296644570b8SJeff Kirsher 
297644570b8SJeff Kirsher 	if (!request_region(ioaddr, NE_IO_EXTENT, DRV_NAME))
298644570b8SJeff Kirsher 		return -EBUSY;
299644570b8SJeff Kirsher 
300644570b8SJeff Kirsher 	reg0 = inb_p(ioaddr);
301644570b8SJeff Kirsher 	if (reg0 == 0xFF) {
302644570b8SJeff Kirsher 		ret = -ENODEV;
303644570b8SJeff Kirsher 		goto err_out;
304644570b8SJeff Kirsher 	}
305644570b8SJeff Kirsher 
306644570b8SJeff Kirsher 	/* Do a preliminary verification that we have a 8390. */
307644570b8SJeff Kirsher 	{
308644570b8SJeff Kirsher 		int regd;
309644570b8SJeff Kirsher 		outb_p(E8390_NODMA+E8390_PAGE1+E8390_STOP, ioaddr + E8390_CMD);
310644570b8SJeff Kirsher 		regd = inb_p(ioaddr + 0x0d);
311644570b8SJeff Kirsher 		outb_p(0xff, ioaddr + 0x0d);
312644570b8SJeff Kirsher 		outb_p(E8390_NODMA+E8390_PAGE0, ioaddr + E8390_CMD);
313644570b8SJeff Kirsher 		inb_p(ioaddr + EN0_COUNTER0); /* Clear the counter by reading. */
314644570b8SJeff Kirsher 		if (inb_p(ioaddr + EN0_COUNTER0) != 0) {
315644570b8SJeff Kirsher 			outb_p(reg0, ioaddr);
316644570b8SJeff Kirsher 			outb_p(regd, ioaddr + 0x0d);	/* Restore the old values. */
317644570b8SJeff Kirsher 			ret = -ENODEV;
318644570b8SJeff Kirsher 			goto err_out;
319644570b8SJeff Kirsher 		}
320644570b8SJeff Kirsher 	}
321644570b8SJeff Kirsher 
322644570b8SJeff Kirsher 	if (ei_debug  &&  version_printed++ == 0)
323644570b8SJeff Kirsher 		printk(KERN_INFO "%s%s", version1, version2);
324644570b8SJeff Kirsher 
325644570b8SJeff Kirsher 	printk(KERN_INFO "NE*000 ethercard probe at %#3lx:", ioaddr);
326644570b8SJeff Kirsher 
327644570b8SJeff Kirsher 	/* A user with a poor card that fails to ack the reset, or that
328644570b8SJeff Kirsher 	   does not have a valid 0x57,0x57 signature can still use this
329644570b8SJeff Kirsher 	   without having to recompile. Specifying an i/o address along
330644570b8SJeff Kirsher 	   with an otherwise unused dev->mem_end value of "0xBAD" will
331644570b8SJeff Kirsher 	   cause the driver to skip these parts of the probe. */
332644570b8SJeff Kirsher 
333644570b8SJeff Kirsher 	bad_card = ((dev->base_addr != 0) && (dev->mem_end == BAD));
334644570b8SJeff Kirsher 
335644570b8SJeff Kirsher 	/* Reset card. Who knows what dain-bramaged state it was left in. */
336644570b8SJeff Kirsher 
337644570b8SJeff Kirsher 	{
338644570b8SJeff Kirsher 		unsigned long reset_start_time = jiffies;
339644570b8SJeff Kirsher 
340644570b8SJeff Kirsher 		/* DON'T change these to inb_p/outb_p or reset will fail on clones. */
341644570b8SJeff Kirsher 		outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET);
342644570b8SJeff Kirsher 
343644570b8SJeff Kirsher 		while ((inb_p(ioaddr + EN0_ISR) & ENISR_RESET) == 0)
344644570b8SJeff Kirsher 		if (time_after(jiffies, reset_start_time + 2*HZ/100)) {
345644570b8SJeff Kirsher 			if (bad_card) {
346644570b8SJeff Kirsher 				printk(" (warning: no reset ack)");
347644570b8SJeff Kirsher 				break;
348644570b8SJeff Kirsher 			} else {
349644570b8SJeff Kirsher 				printk(" not found (no reset ack).\n");
350644570b8SJeff Kirsher 				ret = -ENODEV;
351644570b8SJeff Kirsher 				goto err_out;
352644570b8SJeff Kirsher 			}
353644570b8SJeff Kirsher 		}
354644570b8SJeff Kirsher 
355644570b8SJeff Kirsher 		outb_p(0xff, ioaddr + EN0_ISR);		/* Ack all intr. */
356644570b8SJeff Kirsher 	}
357644570b8SJeff Kirsher 
358644570b8SJeff Kirsher 	/* Read the 16 bytes of station address PROM.
359644570b8SJeff Kirsher 	   We must first initialize registers, similar to NS8390p_init(eifdev, 0).
360644570b8SJeff Kirsher 	   We can't reliably read the SAPROM address without this.
361644570b8SJeff Kirsher 	   (I learned the hard way!). */
362644570b8SJeff Kirsher 	{
363644570b8SJeff Kirsher 		struct {unsigned char value, offset; } program_seq[] =
364644570b8SJeff Kirsher 		{
365644570b8SJeff Kirsher 			{E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
366644570b8SJeff Kirsher 			{0x48,	EN0_DCFG},	/* Set byte-wide (0x48) access. */
367644570b8SJeff Kirsher 			{0x00,	EN0_RCNTLO},	/* Clear the count regs. */
368644570b8SJeff Kirsher 			{0x00,	EN0_RCNTHI},
369644570b8SJeff Kirsher 			{0x00,	EN0_IMR},	/* Mask completion irq. */
370644570b8SJeff Kirsher 			{0xFF,	EN0_ISR},
371644570b8SJeff Kirsher 			{E8390_RXOFF, EN0_RXCR},	/* 0x20  Set to monitor */
372644570b8SJeff Kirsher 			{E8390_TXOFF, EN0_TXCR},	/* 0x02  and loopback mode. */
373644570b8SJeff Kirsher 			{32,	EN0_RCNTLO},
374644570b8SJeff Kirsher 			{0x00,	EN0_RCNTHI},
375644570b8SJeff Kirsher 			{0x00,	EN0_RSARLO},	/* DMA starting at 0x0000. */
376644570b8SJeff Kirsher 			{0x00,	EN0_RSARHI},
377644570b8SJeff Kirsher 			{E8390_RREAD+E8390_START, E8390_CMD},
378644570b8SJeff Kirsher 		};
379644570b8SJeff Kirsher 
380644570b8SJeff Kirsher 		for (i = 0; i < ARRAY_SIZE(program_seq); i++)
381644570b8SJeff Kirsher 			outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
382644570b8SJeff Kirsher 
383644570b8SJeff Kirsher 	}
384644570b8SJeff Kirsher 	for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) {
385644570b8SJeff Kirsher 		SA_prom[i] = inb(ioaddr + NE_DATAPORT);
386644570b8SJeff Kirsher 		SA_prom[i+1] = inb(ioaddr + NE_DATAPORT);
387644570b8SJeff Kirsher 		if (SA_prom[i] != SA_prom[i+1])
388644570b8SJeff Kirsher 			wordlength = 1;
389644570b8SJeff Kirsher 	}
390644570b8SJeff Kirsher 
391644570b8SJeff Kirsher 	if (wordlength == 2)
392644570b8SJeff Kirsher 	{
393644570b8SJeff Kirsher 		for (i = 0; i < 16; i++)
394644570b8SJeff Kirsher 			SA_prom[i] = SA_prom[i+i];
395644570b8SJeff Kirsher 		/* We must set the 8390 for word mode. */
396644570b8SJeff Kirsher 		outb_p(DCR_VAL, ioaddr + EN0_DCFG);
397644570b8SJeff Kirsher 		start_page = NESM_START_PG;
398644570b8SJeff Kirsher 
399644570b8SJeff Kirsher 		/*
400644570b8SJeff Kirsher 		 * Realtek RTL8019AS datasheet says that the PSTOP register
401644570b8SJeff Kirsher 		 * shouldn't exceed 0x60 in 8-bit mode.
402644570b8SJeff Kirsher 		 * This chip can be identified by reading the signature from
403644570b8SJeff Kirsher 		 * the  remote byte count registers (otherwise write-only)...
404644570b8SJeff Kirsher 		 */
405644570b8SJeff Kirsher 		if ((DCR_VAL & 0x01) == 0 &&		/* 8-bit mode */
406644570b8SJeff Kirsher 		    inb(ioaddr + EN0_RCNTLO) == 0x50 &&
407644570b8SJeff Kirsher 		    inb(ioaddr + EN0_RCNTHI) == 0x70)
408644570b8SJeff Kirsher 			stop_page = 0x60;
409644570b8SJeff Kirsher 		else
410644570b8SJeff Kirsher 			stop_page = NESM_STOP_PG;
411644570b8SJeff Kirsher 	} else {
412644570b8SJeff Kirsher 		start_page = NE1SM_START_PG;
413644570b8SJeff Kirsher 		stop_page  = NE1SM_STOP_PG;
414644570b8SJeff Kirsher 	}
415644570b8SJeff Kirsher 
416644570b8SJeff Kirsher #if  defined(CONFIG_PLAT_MAPPI) || defined(CONFIG_PLAT_OAKS32R)
417644570b8SJeff Kirsher 	neX000 = ((SA_prom[14] == 0x57  &&  SA_prom[15] == 0x57)
418644570b8SJeff Kirsher 		|| (SA_prom[14] == 0x42 && SA_prom[15] == 0x42));
419644570b8SJeff Kirsher #else
420644570b8SJeff Kirsher 	neX000 = (SA_prom[14] == 0x57  &&  SA_prom[15] == 0x57);
421644570b8SJeff Kirsher #endif
422644570b8SJeff Kirsher 	ctron =  (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d);
423644570b8SJeff Kirsher 	copam =  (SA_prom[14] == 0x49 && SA_prom[15] == 0x00);
424644570b8SJeff Kirsher 
425644570b8SJeff Kirsher 	/* Set up the rest of the parameters. */
426644570b8SJeff Kirsher 	if (neX000 || bad_card || copam) {
427644570b8SJeff Kirsher 		name = (wordlength == 2) ? "NE2000" : "NE1000";
428644570b8SJeff Kirsher 	}
429644570b8SJeff Kirsher 	else if (ctron)
430644570b8SJeff Kirsher 	{
431644570b8SJeff Kirsher 		name = (wordlength == 2) ? "Ctron-8" : "Ctron-16";
432644570b8SJeff Kirsher 		start_page = 0x01;
433644570b8SJeff Kirsher 		stop_page = (wordlength == 2) ? 0x40 : 0x20;
434644570b8SJeff Kirsher 	}
435644570b8SJeff Kirsher 	else
436644570b8SJeff Kirsher 	{
437644570b8SJeff Kirsher #ifdef SUPPORT_NE_BAD_CLONES
438644570b8SJeff Kirsher 		/* Ack!  Well, there might be a *bad* NE*000 clone there.
439644570b8SJeff Kirsher 		   Check for total bogus addresses. */
440644570b8SJeff Kirsher 		for (i = 0; bad_clone_list[i].name8; i++)
441644570b8SJeff Kirsher 		{
442644570b8SJeff Kirsher 			if (SA_prom[0] == bad_clone_list[i].SAprefix[0] &&
443644570b8SJeff Kirsher 				SA_prom[1] == bad_clone_list[i].SAprefix[1] &&
444644570b8SJeff Kirsher 				SA_prom[2] == bad_clone_list[i].SAprefix[2])
445644570b8SJeff Kirsher 			{
446644570b8SJeff Kirsher 				if (wordlength == 2)
447644570b8SJeff Kirsher 				{
448644570b8SJeff Kirsher 					name = bad_clone_list[i].name16;
449644570b8SJeff Kirsher 				} else {
450644570b8SJeff Kirsher 					name = bad_clone_list[i].name8;
451644570b8SJeff Kirsher 				}
452644570b8SJeff Kirsher 				break;
453644570b8SJeff Kirsher 			}
454644570b8SJeff Kirsher 		}
455644570b8SJeff Kirsher 		if (bad_clone_list[i].name8 == NULL)
456644570b8SJeff Kirsher 		{
457644570b8SJeff Kirsher 			printk(" not found (invalid signature %2.2x %2.2x).\n",
458644570b8SJeff Kirsher 				SA_prom[14], SA_prom[15]);
459644570b8SJeff Kirsher 			ret = -ENXIO;
460644570b8SJeff Kirsher 			goto err_out;
461644570b8SJeff Kirsher 		}
462644570b8SJeff Kirsher #else
463644570b8SJeff Kirsher 		printk(" not found.\n");
464644570b8SJeff Kirsher 		ret = -ENXIO;
465644570b8SJeff Kirsher 		goto err_out;
466644570b8SJeff Kirsher #endif
467644570b8SJeff Kirsher 	}
468644570b8SJeff Kirsher 
469644570b8SJeff Kirsher 	if (dev->irq < 2)
470644570b8SJeff Kirsher 	{
471644570b8SJeff Kirsher 		unsigned long cookie = probe_irq_on();
472644570b8SJeff Kirsher 		outb_p(0x50, ioaddr + EN0_IMR);	/* Enable one interrupt. */
473644570b8SJeff Kirsher 		outb_p(0x00, ioaddr + EN0_RCNTLO);
474644570b8SJeff Kirsher 		outb_p(0x00, ioaddr + EN0_RCNTHI);
475644570b8SJeff Kirsher 		outb_p(E8390_RREAD+E8390_START, ioaddr); /* Trigger it... */
476644570b8SJeff Kirsher 		mdelay(10);		/* wait 10ms for interrupt to propagate */
477644570b8SJeff Kirsher 		outb_p(0x00, ioaddr + EN0_IMR); 		/* Mask it again. */
478644570b8SJeff Kirsher 		dev->irq = probe_irq_off(cookie);
479644570b8SJeff Kirsher 		if (ei_debug > 2)
480644570b8SJeff Kirsher 			printk(" autoirq is %d\n", dev->irq);
481644570b8SJeff Kirsher 	} else if (dev->irq == 2)
482644570b8SJeff Kirsher 		/* Fixup for users that don't know that IRQ 2 is really IRQ 9,
483644570b8SJeff Kirsher 		   or don't know which one to set. */
484644570b8SJeff Kirsher 		dev->irq = 9;
485644570b8SJeff Kirsher 
486644570b8SJeff Kirsher 	if (! dev->irq) {
487644570b8SJeff Kirsher 		printk(" failed to detect IRQ line.\n");
488644570b8SJeff Kirsher 		ret = -EAGAIN;
489644570b8SJeff Kirsher 		goto err_out;
490644570b8SJeff Kirsher 	}
491644570b8SJeff Kirsher 
492644570b8SJeff Kirsher 	/* Snarf the interrupt now.  There's no point in waiting since we cannot
493644570b8SJeff Kirsher 	   share and the board will usually be enabled. */
494644570b8SJeff Kirsher 	ret = request_irq(dev->irq, eip_interrupt, 0, name, dev);
495644570b8SJeff Kirsher 	if (ret) {
496644570b8SJeff Kirsher 		printk (" unable to get IRQ %d (errno=%d).\n", dev->irq, ret);
497644570b8SJeff Kirsher 		goto err_out;
498644570b8SJeff Kirsher 	}
499644570b8SJeff Kirsher 
500644570b8SJeff Kirsher 	dev->base_addr = ioaddr;
501644570b8SJeff Kirsher 
502644570b8SJeff Kirsher #ifdef CONFIG_PLAT_MAPPI
503644570b8SJeff Kirsher 	outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP,
504644570b8SJeff Kirsher 		ioaddr + E8390_CMD); /* 0x61 */
505104bf3fbSJoe Perches 	for (i = 0; i < ETH_ALEN; i++) {
506644570b8SJeff Kirsher 		dev->dev_addr[i] = SA_prom[i]
507644570b8SJeff Kirsher 			= inb_p(ioaddr + EN1_PHYS_SHIFT(i));
508644570b8SJeff Kirsher 	}
509644570b8SJeff Kirsher #else
510104bf3fbSJoe Perches 	for (i = 0; i < ETH_ALEN; i++) {
511644570b8SJeff Kirsher 		dev->dev_addr[i] = SA_prom[i];
512644570b8SJeff Kirsher 	}
513644570b8SJeff Kirsher #endif
514644570b8SJeff Kirsher 
515644570b8SJeff Kirsher 	printk("%pM\n", dev->dev_addr);
516644570b8SJeff Kirsher 
517644570b8SJeff Kirsher 	ei_status.name = name;
518644570b8SJeff Kirsher 	ei_status.tx_start_page = start_page;
519644570b8SJeff Kirsher 	ei_status.stop_page = stop_page;
520644570b8SJeff Kirsher 
521644570b8SJeff Kirsher 	/* Use 16-bit mode only if this wasn't overridden by DCR_VAL */
522644570b8SJeff Kirsher 	ei_status.word16 = (wordlength == 2 && (DCR_VAL & 0x01));
523644570b8SJeff Kirsher 
524644570b8SJeff Kirsher 	ei_status.rx_start_page = start_page + TX_PAGES;
525644570b8SJeff Kirsher #ifdef PACKETBUF_MEMSIZE
526644570b8SJeff Kirsher 	 /* Allow the packet buffer size to be overridden by know-it-alls. */
527644570b8SJeff Kirsher 	ei_status.stop_page = ei_status.tx_start_page + PACKETBUF_MEMSIZE;
528644570b8SJeff Kirsher #endif
529644570b8SJeff Kirsher 
530644570b8SJeff Kirsher 	ei_status.reset_8390 = &ne_reset_8390;
531644570b8SJeff Kirsher 	ei_status.block_input = &ne_block_input;
532644570b8SJeff Kirsher 	ei_status.block_output = &ne_block_output;
533644570b8SJeff Kirsher 	ei_status.get_8390_hdr = &ne_get_8390_hdr;
534644570b8SJeff Kirsher 	ei_status.priv = 0;
535644570b8SJeff Kirsher 
536644570b8SJeff Kirsher 	dev->netdev_ops = &eip_netdev_ops;
537644570b8SJeff Kirsher 	NS8390p_init(dev, 0);
538644570b8SJeff Kirsher 
539644570b8SJeff Kirsher 	ret = register_netdev(dev);
540644570b8SJeff Kirsher 	if (ret)
541644570b8SJeff Kirsher 		goto out_irq;
542644570b8SJeff Kirsher 	printk(KERN_INFO "%s: %s found at %#lx, using IRQ %d.\n",
543644570b8SJeff Kirsher 	       dev->name, name, ioaddr, dev->irq);
544644570b8SJeff Kirsher 	return 0;
545644570b8SJeff Kirsher 
546644570b8SJeff Kirsher out_irq:
547644570b8SJeff Kirsher 	free_irq(dev->irq, dev);
548644570b8SJeff Kirsher err_out:
549644570b8SJeff Kirsher 	release_region(ioaddr, NE_IO_EXTENT);
550644570b8SJeff Kirsher 	return ret;
551644570b8SJeff Kirsher }
552644570b8SJeff Kirsher 
553644570b8SJeff Kirsher /* Hard reset the card.  This used to pause for the same period that a
554644570b8SJeff Kirsher    8390 reset command required, but that shouldn't be necessary. */
555644570b8SJeff Kirsher 
556644570b8SJeff Kirsher static void ne_reset_8390(struct net_device *dev)
557644570b8SJeff Kirsher {
558644570b8SJeff Kirsher 	unsigned long reset_start_time = jiffies;
559644570b8SJeff Kirsher 
560644570b8SJeff Kirsher 	if (ei_debug > 1)
561644570b8SJeff Kirsher 		printk(KERN_DEBUG "resetting the 8390 t=%ld...", jiffies);
562644570b8SJeff Kirsher 
563644570b8SJeff Kirsher 	/* DON'T change these to inb_p/outb_p or reset will fail on clones. */
564644570b8SJeff Kirsher 	outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET);
565644570b8SJeff Kirsher 
566644570b8SJeff Kirsher 	ei_status.txing = 0;
567644570b8SJeff Kirsher 	ei_status.dmaing = 0;
568644570b8SJeff Kirsher 
569644570b8SJeff Kirsher 	/* This check _should_not_ be necessary, omit eventually. */
570644570b8SJeff Kirsher 	while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0)
571644570b8SJeff Kirsher 		if (time_after(jiffies, reset_start_time + 2*HZ/100)) {
572644570b8SJeff Kirsher 			printk(KERN_WARNING "%s: ne_reset_8390() did not complete.\n", dev->name);
573644570b8SJeff Kirsher 			break;
574644570b8SJeff Kirsher 		}
575644570b8SJeff Kirsher 	outb_p(ENISR_RESET, NE_BASE + EN0_ISR);	/* Ack intr. */
576644570b8SJeff Kirsher }
577644570b8SJeff Kirsher 
578644570b8SJeff Kirsher /* Grab the 8390 specific header. Similar to the block_input routine, but
579644570b8SJeff Kirsher    we don't need to be concerned with ring wrap as the header will be at
580644570b8SJeff Kirsher    the start of a page, so we optimize accordingly. */
581644570b8SJeff Kirsher 
582644570b8SJeff Kirsher static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
583644570b8SJeff Kirsher {
584644570b8SJeff Kirsher 	int nic_base = dev->base_addr;
585644570b8SJeff Kirsher 
586644570b8SJeff Kirsher 	/* This *shouldn't* happen. If it does, it's the last thing you'll see */
587644570b8SJeff Kirsher 
588644570b8SJeff Kirsher 	if (ei_status.dmaing)
589644570b8SJeff Kirsher 	{
590644570b8SJeff Kirsher 		printk(KERN_EMERG "%s: DMAing conflict in ne_get_8390_hdr "
591644570b8SJeff Kirsher 			"[DMAstat:%d][irqlock:%d].\n",
592644570b8SJeff Kirsher 			dev->name, ei_status.dmaing, ei_status.irqlock);
593644570b8SJeff Kirsher 		return;
594644570b8SJeff Kirsher 	}
595644570b8SJeff Kirsher 
596644570b8SJeff Kirsher 	ei_status.dmaing |= 0x01;
597644570b8SJeff Kirsher 	outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
598644570b8SJeff Kirsher 	outb_p(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO);
599644570b8SJeff Kirsher 	outb_p(0, nic_base + EN0_RCNTHI);
600644570b8SJeff Kirsher 	outb_p(0, nic_base + EN0_RSARLO);		/* On page boundary */
601644570b8SJeff Kirsher 	outb_p(ring_page, nic_base + EN0_RSARHI);
602644570b8SJeff Kirsher 	outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
603644570b8SJeff Kirsher 
604644570b8SJeff Kirsher 	if (ei_status.word16)
605644570b8SJeff Kirsher 		insw(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
606644570b8SJeff Kirsher 	else
607644570b8SJeff Kirsher 		insb(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr));
608644570b8SJeff Kirsher 
609644570b8SJeff Kirsher 	outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
610644570b8SJeff Kirsher 	ei_status.dmaing &= ~0x01;
611644570b8SJeff Kirsher 
612644570b8SJeff Kirsher 	le16_to_cpus(&hdr->count);
613644570b8SJeff Kirsher }
614644570b8SJeff Kirsher 
615644570b8SJeff Kirsher /* Block input and output, similar to the Crynwr packet driver.  If you
616644570b8SJeff Kirsher    are porting to a new ethercard, look at the packet driver source for hints.
617644570b8SJeff Kirsher    The NEx000 doesn't share the on-board packet memory -- you have to put
618644570b8SJeff Kirsher    the packet out through the "remote DMA" dataport using outb. */
619644570b8SJeff Kirsher 
620644570b8SJeff Kirsher static void ne_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
621644570b8SJeff Kirsher {
622644570b8SJeff Kirsher #ifdef NE_SANITY_CHECK
623644570b8SJeff Kirsher 	int xfer_count = count;
624644570b8SJeff Kirsher #endif
625644570b8SJeff Kirsher 	int nic_base = dev->base_addr;
626644570b8SJeff Kirsher 	char *buf = skb->data;
627644570b8SJeff Kirsher 
628644570b8SJeff Kirsher 	/* This *shouldn't* happen. If it does, it's the last thing you'll see */
629644570b8SJeff Kirsher 	if (ei_status.dmaing)
630644570b8SJeff Kirsher 	{
631644570b8SJeff Kirsher 		printk(KERN_EMERG "%s: DMAing conflict in ne_block_input "
632644570b8SJeff Kirsher 			"[DMAstat:%d][irqlock:%d].\n",
633644570b8SJeff Kirsher 			dev->name, ei_status.dmaing, ei_status.irqlock);
634644570b8SJeff Kirsher 		return;
635644570b8SJeff Kirsher 	}
636644570b8SJeff Kirsher 	ei_status.dmaing |= 0x01;
637644570b8SJeff Kirsher 	outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
638644570b8SJeff Kirsher 	outb_p(count & 0xff, nic_base + EN0_RCNTLO);
639644570b8SJeff Kirsher 	outb_p(count >> 8, nic_base + EN0_RCNTHI);
640644570b8SJeff Kirsher 	outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
641644570b8SJeff Kirsher 	outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
642644570b8SJeff Kirsher 	outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
643644570b8SJeff Kirsher 	if (ei_status.word16)
644644570b8SJeff Kirsher 	{
645644570b8SJeff Kirsher 		insw(NE_BASE + NE_DATAPORT,buf,count>>1);
646644570b8SJeff Kirsher 		if (count & 0x01)
647644570b8SJeff Kirsher 		{
648644570b8SJeff Kirsher 			buf[count-1] = inb(NE_BASE + NE_DATAPORT);
649644570b8SJeff Kirsher #ifdef NE_SANITY_CHECK
650644570b8SJeff Kirsher 			xfer_count++;
651644570b8SJeff Kirsher #endif
652644570b8SJeff Kirsher 		}
653644570b8SJeff Kirsher 	} else {
654644570b8SJeff Kirsher 		insb(NE_BASE + NE_DATAPORT, buf, count);
655644570b8SJeff Kirsher 	}
656644570b8SJeff Kirsher 
657644570b8SJeff Kirsher #ifdef NE_SANITY_CHECK
658644570b8SJeff Kirsher 	/* This was for the ALPHA version only, but enough people have
659644570b8SJeff Kirsher 	   been encountering problems so it is still here.  If you see
660644570b8SJeff Kirsher 	   this message you either 1) have a slightly incompatible clone
661644570b8SJeff Kirsher 	   or 2) have noise/speed problems with your bus. */
662644570b8SJeff Kirsher 
663644570b8SJeff Kirsher 	if (ei_debug > 1)
664644570b8SJeff Kirsher 	{
665644570b8SJeff Kirsher 		/* DMA termination address check... */
666644570b8SJeff Kirsher 		int addr, tries = 20;
667644570b8SJeff Kirsher 		do {
668644570b8SJeff Kirsher 			/* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here
669644570b8SJeff Kirsher 			   -- it's broken for Rx on some cards! */
670644570b8SJeff Kirsher 			int high = inb_p(nic_base + EN0_RSARHI);
671644570b8SJeff Kirsher 			int low = inb_p(nic_base + EN0_RSARLO);
672644570b8SJeff Kirsher 			addr = (high << 8) + low;
673644570b8SJeff Kirsher 			if (((ring_offset + xfer_count) & 0xff) == low)
674644570b8SJeff Kirsher 				break;
675644570b8SJeff Kirsher 		} while (--tries > 0);
676644570b8SJeff Kirsher 	 	if (tries <= 0)
677644570b8SJeff Kirsher 			printk(KERN_WARNING "%s: RX transfer address mismatch,"
678644570b8SJeff Kirsher 				"%#4.4x (expected) vs. %#4.4x (actual).\n",
679644570b8SJeff Kirsher 				dev->name, ring_offset + xfer_count, addr);
680644570b8SJeff Kirsher 	}
681644570b8SJeff Kirsher #endif
682644570b8SJeff Kirsher 	outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
683644570b8SJeff Kirsher 	ei_status.dmaing &= ~0x01;
684644570b8SJeff Kirsher }
685644570b8SJeff Kirsher 
686644570b8SJeff Kirsher static void ne_block_output(struct net_device *dev, int count,
687644570b8SJeff Kirsher 		const unsigned char *buf, const int start_page)
688644570b8SJeff Kirsher {
689644570b8SJeff Kirsher 	int nic_base = NE_BASE;
690644570b8SJeff Kirsher 	unsigned long dma_start;
691644570b8SJeff Kirsher #ifdef NE_SANITY_CHECK
692644570b8SJeff Kirsher 	int retries = 0;
693644570b8SJeff Kirsher #endif
694644570b8SJeff Kirsher 
695644570b8SJeff Kirsher 	/* Round the count up for word writes.  Do we need to do this?
696644570b8SJeff Kirsher 	   What effect will an odd byte count have on the 8390?
697644570b8SJeff Kirsher 	   I should check someday. */
698644570b8SJeff Kirsher 
699644570b8SJeff Kirsher 	if (ei_status.word16 && (count & 0x01))
700644570b8SJeff Kirsher 		count++;
701644570b8SJeff Kirsher 
702644570b8SJeff Kirsher 	/* This *shouldn't* happen. If it does, it's the last thing you'll see */
703644570b8SJeff Kirsher 	if (ei_status.dmaing)
704644570b8SJeff Kirsher 	{
705644570b8SJeff Kirsher 		printk(KERN_EMERG "%s: DMAing conflict in ne_block_output."
706644570b8SJeff Kirsher 			"[DMAstat:%d][irqlock:%d]\n",
707644570b8SJeff Kirsher 			dev->name, ei_status.dmaing, ei_status.irqlock);
708644570b8SJeff Kirsher 		return;
709644570b8SJeff Kirsher 	}
710644570b8SJeff Kirsher 	ei_status.dmaing |= 0x01;
711644570b8SJeff Kirsher 	/* We should already be in page 0, but to be safe... */
712644570b8SJeff Kirsher 	outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD);
713644570b8SJeff Kirsher 
714644570b8SJeff Kirsher #ifdef NE_SANITY_CHECK
715644570b8SJeff Kirsher retry:
716644570b8SJeff Kirsher #endif
717644570b8SJeff Kirsher 
718644570b8SJeff Kirsher #ifdef NE8390_RW_BUGFIX
719644570b8SJeff Kirsher 	/* Handle the read-before-write bug the same way as the
720644570b8SJeff Kirsher 	   Crynwr packet driver -- the NatSemi method doesn't work.
721644570b8SJeff Kirsher 	   Actually this doesn't always work either, but if you have
722644570b8SJeff Kirsher 	   problems with your NEx000 this is better than nothing! */
723644570b8SJeff Kirsher 
724644570b8SJeff Kirsher 	outb_p(0x42, nic_base + EN0_RCNTLO);
725644570b8SJeff Kirsher 	outb_p(0x00,   nic_base + EN0_RCNTHI);
726644570b8SJeff Kirsher 	outb_p(0x42, nic_base + EN0_RSARLO);
727644570b8SJeff Kirsher 	outb_p(0x00, nic_base + EN0_RSARHI);
728644570b8SJeff Kirsher 	outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
729644570b8SJeff Kirsher 	/* Make certain that the dummy read has occurred. */
730644570b8SJeff Kirsher 	udelay(6);
731644570b8SJeff Kirsher #endif
732644570b8SJeff Kirsher 
733644570b8SJeff Kirsher 	outb_p(ENISR_RDC, nic_base + EN0_ISR);
734644570b8SJeff Kirsher 
735644570b8SJeff Kirsher 	/* Now the normal output. */
736644570b8SJeff Kirsher 	outb_p(count & 0xff, nic_base + EN0_RCNTLO);
737644570b8SJeff Kirsher 	outb_p(count >> 8,   nic_base + EN0_RCNTHI);
738644570b8SJeff Kirsher 	outb_p(0x00, nic_base + EN0_RSARLO);
739644570b8SJeff Kirsher 	outb_p(start_page, nic_base + EN0_RSARHI);
740644570b8SJeff Kirsher 
741644570b8SJeff Kirsher 	outb_p(E8390_RWRITE+E8390_START, nic_base + NE_CMD);
742644570b8SJeff Kirsher 	if (ei_status.word16) {
743644570b8SJeff Kirsher 		outsw(NE_BASE + NE_DATAPORT, buf, count>>1);
744644570b8SJeff Kirsher 	} else {
745644570b8SJeff Kirsher 		outsb(NE_BASE + NE_DATAPORT, buf, count);
746644570b8SJeff Kirsher 	}
747644570b8SJeff Kirsher 
748644570b8SJeff Kirsher 	dma_start = jiffies;
749644570b8SJeff Kirsher 
750644570b8SJeff Kirsher #ifdef NE_SANITY_CHECK
751644570b8SJeff Kirsher 	/* This was for the ALPHA version only, but enough people have
752644570b8SJeff Kirsher 	   been encountering problems so it is still here. */
753644570b8SJeff Kirsher 
754644570b8SJeff Kirsher 	if (ei_debug > 1)
755644570b8SJeff Kirsher 	{
756644570b8SJeff Kirsher 		/* DMA termination address check... */
757644570b8SJeff Kirsher 		int addr, tries = 20;
758644570b8SJeff Kirsher 		do {
759644570b8SJeff Kirsher 			int high = inb_p(nic_base + EN0_RSARHI);
760644570b8SJeff Kirsher 			int low = inb_p(nic_base + EN0_RSARLO);
761644570b8SJeff Kirsher 			addr = (high << 8) + low;
762644570b8SJeff Kirsher 			if ((start_page << 8) + count == addr)
763644570b8SJeff Kirsher 				break;
764644570b8SJeff Kirsher 		} while (--tries > 0);
765644570b8SJeff Kirsher 
766644570b8SJeff Kirsher 		if (tries <= 0)
767644570b8SJeff Kirsher 		{
768644570b8SJeff Kirsher 			printk(KERN_WARNING "%s: Tx packet transfer address mismatch,"
769644570b8SJeff Kirsher 				"%#4.4x (expected) vs. %#4.4x (actual).\n",
770644570b8SJeff Kirsher 				dev->name, (start_page << 8) + count, addr);
771644570b8SJeff Kirsher 			if (retries++ == 0)
772644570b8SJeff Kirsher 				goto retry;
773644570b8SJeff Kirsher 		}
774644570b8SJeff Kirsher 	}
775644570b8SJeff Kirsher #endif
776644570b8SJeff Kirsher 
777644570b8SJeff Kirsher 	while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0)
778644570b8SJeff Kirsher 		if (time_after(jiffies, dma_start + 2*HZ/100)) {		/* 20ms */
779644570b8SJeff Kirsher 			printk(KERN_WARNING "%s: timeout waiting for Tx RDC.\n", dev->name);
780644570b8SJeff Kirsher 			ne_reset_8390(dev);
781644570b8SJeff Kirsher 			NS8390p_init(dev, 1);
782644570b8SJeff Kirsher 			break;
783644570b8SJeff Kirsher 		}
784644570b8SJeff Kirsher 
785644570b8SJeff Kirsher 	outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
786644570b8SJeff Kirsher 	ei_status.dmaing &= ~0x01;
787644570b8SJeff Kirsher }
788644570b8SJeff Kirsher 
789644570b8SJeff Kirsher static int __init ne_drv_probe(struct platform_device *pdev)
790644570b8SJeff Kirsher {
791644570b8SJeff Kirsher 	struct net_device *dev;
792644570b8SJeff Kirsher 	int err, this_dev = pdev->id;
793644570b8SJeff Kirsher 	struct resource *res;
794644570b8SJeff Kirsher 
795644570b8SJeff Kirsher 	dev = alloc_eip_netdev();
796644570b8SJeff Kirsher 	if (!dev)
797644570b8SJeff Kirsher 		return -ENOMEM;
798644570b8SJeff Kirsher 
799644570b8SJeff Kirsher 	/* ne.c doesn't populate resources in platform_device, but
800644570b8SJeff Kirsher 	 * rbtx4927_ne_init and rbtx4938_ne_init do register devices
801644570b8SJeff Kirsher 	 * with resources.
802644570b8SJeff Kirsher 	 */
803644570b8SJeff Kirsher 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
804644570b8SJeff Kirsher 	if (res) {
805644570b8SJeff Kirsher 		dev->base_addr = res->start;
806644570b8SJeff Kirsher 		dev->irq = platform_get_irq(pdev, 0);
807644570b8SJeff Kirsher 	} else {
808644570b8SJeff Kirsher 		if (this_dev < 0 || this_dev >= MAX_NE_CARDS) {
809644570b8SJeff Kirsher 			free_netdev(dev);
810644570b8SJeff Kirsher 			return -EINVAL;
811644570b8SJeff Kirsher 		}
812644570b8SJeff Kirsher 		dev->base_addr = io[this_dev];
813644570b8SJeff Kirsher 		dev->irq = irq[this_dev];
814644570b8SJeff Kirsher 		dev->mem_end = bad[this_dev];
815644570b8SJeff Kirsher 	}
816da9da01dSAlan Cox 	SET_NETDEV_DEV(dev, &pdev->dev);
817644570b8SJeff Kirsher 	err = do_ne_probe(dev);
818644570b8SJeff Kirsher 	if (err) {
819644570b8SJeff Kirsher 		free_netdev(dev);
820644570b8SJeff Kirsher 		return err;
821644570b8SJeff Kirsher 	}
822644570b8SJeff Kirsher 	platform_set_drvdata(pdev, dev);
823644570b8SJeff Kirsher 
824644570b8SJeff Kirsher 	/* Update with any values found by probing, don't update if
825644570b8SJeff Kirsher 	 * resources were specified.
826644570b8SJeff Kirsher 	 */
827644570b8SJeff Kirsher 	if (!res) {
828644570b8SJeff Kirsher 		io[this_dev] = dev->base_addr;
829644570b8SJeff Kirsher 		irq[this_dev] = dev->irq;
830644570b8SJeff Kirsher 	}
831644570b8SJeff Kirsher 	return 0;
832644570b8SJeff Kirsher }
833644570b8SJeff Kirsher 
834644570b8SJeff Kirsher static int ne_drv_remove(struct platform_device *pdev)
835644570b8SJeff Kirsher {
836644570b8SJeff Kirsher 	struct net_device *dev = platform_get_drvdata(pdev);
837644570b8SJeff Kirsher 
838644570b8SJeff Kirsher 	if (dev) {
839644570b8SJeff Kirsher 		struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv;
840644570b8SJeff Kirsher 		netif_device_detach(dev);
841644570b8SJeff Kirsher 		unregister_netdev(dev);
842644570b8SJeff Kirsher 		if (idev)
843644570b8SJeff Kirsher 			pnp_device_detach(idev);
844644570b8SJeff Kirsher 		/* Careful ne_drv_remove can be called twice, once from
845644570b8SJeff Kirsher 		 * the platform_driver.remove and again when the
846644570b8SJeff Kirsher 		 * platform_device is being removed.
847644570b8SJeff Kirsher 		 */
848644570b8SJeff Kirsher 		ei_status.priv = 0;
849644570b8SJeff Kirsher 		free_irq(dev->irq, dev);
850644570b8SJeff Kirsher 		release_region(dev->base_addr, NE_IO_EXTENT);
851644570b8SJeff Kirsher 		free_netdev(dev);
852644570b8SJeff Kirsher 		platform_set_drvdata(pdev, NULL);
853644570b8SJeff Kirsher 	}
854644570b8SJeff Kirsher 	return 0;
855644570b8SJeff Kirsher }
856644570b8SJeff Kirsher 
857644570b8SJeff Kirsher /* Remove unused devices or all if true. */
858644570b8SJeff Kirsher static void ne_loop_rm_unreg(int all)
859644570b8SJeff Kirsher {
860644570b8SJeff Kirsher 	int this_dev;
861644570b8SJeff Kirsher 	struct platform_device *pdev;
862644570b8SJeff Kirsher 	for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
863644570b8SJeff Kirsher 		pdev = pdev_ne[this_dev];
864644570b8SJeff Kirsher 		/* No network device == unused */
865644570b8SJeff Kirsher 		if (pdev && (!platform_get_drvdata(pdev) || all)) {
866644570b8SJeff Kirsher 			ne_drv_remove(pdev);
867644570b8SJeff Kirsher 			platform_device_unregister(pdev);
868644570b8SJeff Kirsher 			pdev_ne[this_dev] = NULL;
869644570b8SJeff Kirsher 		}
870644570b8SJeff Kirsher 	}
871644570b8SJeff Kirsher }
872644570b8SJeff Kirsher 
873644570b8SJeff Kirsher #ifdef CONFIG_PM
874644570b8SJeff Kirsher static int ne_drv_suspend(struct platform_device *pdev, pm_message_t state)
875644570b8SJeff Kirsher {
876644570b8SJeff Kirsher 	struct net_device *dev = platform_get_drvdata(pdev);
877644570b8SJeff Kirsher 
878644570b8SJeff Kirsher 	if (netif_running(dev)) {
879644570b8SJeff Kirsher 		struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv;
880644570b8SJeff Kirsher 		netif_device_detach(dev);
881644570b8SJeff Kirsher 		if (idev)
882644570b8SJeff Kirsher 			pnp_stop_dev(idev);
883644570b8SJeff Kirsher 	}
884644570b8SJeff Kirsher 	return 0;
885644570b8SJeff Kirsher }
886644570b8SJeff Kirsher 
887644570b8SJeff Kirsher static int ne_drv_resume(struct platform_device *pdev)
888644570b8SJeff Kirsher {
889644570b8SJeff Kirsher 	struct net_device *dev = platform_get_drvdata(pdev);
890644570b8SJeff Kirsher 
891644570b8SJeff Kirsher 	if (netif_running(dev)) {
892644570b8SJeff Kirsher 		struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv;
893644570b8SJeff Kirsher 		if (idev)
894644570b8SJeff Kirsher 			pnp_start_dev(idev);
895644570b8SJeff Kirsher 		ne_reset_8390(dev);
896644570b8SJeff Kirsher 		NS8390p_init(dev, 1);
897644570b8SJeff Kirsher 		netif_device_attach(dev);
898644570b8SJeff Kirsher 	}
899644570b8SJeff Kirsher 	return 0;
900644570b8SJeff Kirsher }
901644570b8SJeff Kirsher #else
902644570b8SJeff Kirsher #define ne_drv_suspend NULL
903644570b8SJeff Kirsher #define ne_drv_resume NULL
904644570b8SJeff Kirsher #endif
905644570b8SJeff Kirsher 
906644570b8SJeff Kirsher static struct platform_driver ne_driver = {
907644570b8SJeff Kirsher 	.remove		= ne_drv_remove,
908644570b8SJeff Kirsher 	.suspend	= ne_drv_suspend,
909644570b8SJeff Kirsher 	.resume		= ne_drv_resume,
910644570b8SJeff Kirsher 	.driver		= {
911644570b8SJeff Kirsher 		.name	= DRV_NAME,
912644570b8SJeff Kirsher 		.owner	= THIS_MODULE,
913644570b8SJeff Kirsher 	},
914644570b8SJeff Kirsher };
915644570b8SJeff Kirsher 
916644570b8SJeff Kirsher static void __init ne_add_devices(void)
917644570b8SJeff Kirsher {
918644570b8SJeff Kirsher 	int this_dev;
919644570b8SJeff Kirsher 	struct platform_device *pdev;
920644570b8SJeff Kirsher 
921644570b8SJeff Kirsher 	for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
922644570b8SJeff Kirsher 		if (pdev_ne[this_dev])
923644570b8SJeff Kirsher 			continue;
924644570b8SJeff Kirsher 		pdev = platform_device_register_simple(
925644570b8SJeff Kirsher 			DRV_NAME, this_dev, NULL, 0);
926644570b8SJeff Kirsher 		if (IS_ERR(pdev))
927644570b8SJeff Kirsher 			continue;
928644570b8SJeff Kirsher 		pdev_ne[this_dev] = pdev;
929644570b8SJeff Kirsher 	}
930644570b8SJeff Kirsher }
931644570b8SJeff Kirsher 
932644570b8SJeff Kirsher #ifdef MODULE
933644570b8SJeff Kirsher int __init init_module(void)
934644570b8SJeff Kirsher {
935644570b8SJeff Kirsher 	int retval;
936644570b8SJeff Kirsher 	ne_add_devices();
937644570b8SJeff Kirsher 	retval = platform_driver_probe(&ne_driver, ne_drv_probe);
938644570b8SJeff Kirsher 	if (retval) {
939644570b8SJeff Kirsher 		if (io[0] == 0)
940644570b8SJeff Kirsher 			printk(KERN_NOTICE "ne.c: You must supply \"io=0xNNN\""
941644570b8SJeff Kirsher 				" value(s) for ISA cards.\n");
942644570b8SJeff Kirsher 		ne_loop_rm_unreg(1);
943644570b8SJeff Kirsher 		return retval;
944644570b8SJeff Kirsher 	}
945644570b8SJeff Kirsher 
946644570b8SJeff Kirsher 	/* Unregister unused platform_devices. */
947644570b8SJeff Kirsher 	ne_loop_rm_unreg(0);
948644570b8SJeff Kirsher 	return retval;
949644570b8SJeff Kirsher }
950644570b8SJeff Kirsher #else /* MODULE */
951644570b8SJeff Kirsher static int __init ne_init(void)
952644570b8SJeff Kirsher {
953644570b8SJeff Kirsher 	int retval = platform_driver_probe(&ne_driver, ne_drv_probe);
954644570b8SJeff Kirsher 
955644570b8SJeff Kirsher 	/* Unregister unused platform_devices. */
956644570b8SJeff Kirsher 	ne_loop_rm_unreg(0);
957644570b8SJeff Kirsher 	return retval;
958644570b8SJeff Kirsher }
959644570b8SJeff Kirsher module_init(ne_init);
960644570b8SJeff Kirsher 
961644570b8SJeff Kirsher struct net_device * __init ne_probe(int unit)
962644570b8SJeff Kirsher {
963644570b8SJeff Kirsher 	int this_dev;
964644570b8SJeff Kirsher 	struct net_device *dev;
965644570b8SJeff Kirsher 
966644570b8SJeff Kirsher 	/* Find an empty slot, that is no net_device and zero io port. */
967644570b8SJeff Kirsher 	this_dev = 0;
968644570b8SJeff Kirsher 	while ((pdev_ne[this_dev] && platform_get_drvdata(pdev_ne[this_dev])) ||
969644570b8SJeff Kirsher 		io[this_dev]) {
970644570b8SJeff Kirsher 		if (++this_dev == MAX_NE_CARDS)
971644570b8SJeff Kirsher 			return ERR_PTR(-ENOMEM);
972644570b8SJeff Kirsher 	}
973644570b8SJeff Kirsher 
974644570b8SJeff Kirsher 	/* Get irq, io from kernel command line */
975644570b8SJeff Kirsher 	dev = alloc_eip_netdev();
976644570b8SJeff Kirsher 	if (!dev)
977644570b8SJeff Kirsher 		return ERR_PTR(-ENOMEM);
978644570b8SJeff Kirsher 
979644570b8SJeff Kirsher 	sprintf(dev->name, "eth%d", unit);
980644570b8SJeff Kirsher 	netdev_boot_setup_check(dev);
981644570b8SJeff Kirsher 
982644570b8SJeff Kirsher 	io[this_dev] = dev->base_addr;
983644570b8SJeff Kirsher 	irq[this_dev] = dev->irq;
984644570b8SJeff Kirsher 	bad[this_dev] = dev->mem_end;
985644570b8SJeff Kirsher 
986644570b8SJeff Kirsher 	free_netdev(dev);
987644570b8SJeff Kirsher 
988644570b8SJeff Kirsher 	ne_add_devices();
989644570b8SJeff Kirsher 
990644570b8SJeff Kirsher 	/* return the first device found */
991644570b8SJeff Kirsher 	for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
992644570b8SJeff Kirsher 		if (pdev_ne[this_dev]) {
993644570b8SJeff Kirsher 			dev = platform_get_drvdata(pdev_ne[this_dev]);
994644570b8SJeff Kirsher 			if (dev)
995644570b8SJeff Kirsher 				return dev;
996644570b8SJeff Kirsher 		}
997644570b8SJeff Kirsher 	}
998644570b8SJeff Kirsher 
999644570b8SJeff Kirsher 	return ERR_PTR(-ENODEV);
1000644570b8SJeff Kirsher }
1001644570b8SJeff Kirsher #endif /* MODULE */
1002644570b8SJeff Kirsher 
1003644570b8SJeff Kirsher static void __exit ne_exit(void)
1004644570b8SJeff Kirsher {
1005644570b8SJeff Kirsher 	platform_driver_unregister(&ne_driver);
1006644570b8SJeff Kirsher 	ne_loop_rm_unreg(1);
1007644570b8SJeff Kirsher }
1008644570b8SJeff Kirsher module_exit(ne_exit);
1009