xref: /openbmc/linux/drivers/net/ethernet/8390/apne.c (revision c45f812f)
1644570b8SJeff Kirsher /*
2644570b8SJeff Kirsher  * Amiga Linux/68k 8390 based PCMCIA Ethernet Driver for the Amiga 1200
3644570b8SJeff Kirsher  *
4644570b8SJeff Kirsher  * (C) Copyright 1997 Alain Malek
5644570b8SJeff Kirsher  *                    (Alain.Malek@cryogen.com)
6644570b8SJeff Kirsher  *
7644570b8SJeff Kirsher  * ----------------------------------------------------------------------------
8644570b8SJeff Kirsher  *
9644570b8SJeff Kirsher  * This program is based on
10644570b8SJeff Kirsher  *
11644570b8SJeff Kirsher  * ne.c:       A general non-shared-memory NS8390 ethernet driver for linux
12644570b8SJeff Kirsher  *             Written 1992-94 by Donald Becker.
13644570b8SJeff Kirsher  *
14644570b8SJeff Kirsher  * 8390.c:     A general NS8390 ethernet driver core for linux.
15644570b8SJeff Kirsher  *             Written 1992-94 by Donald Becker.
16644570b8SJeff Kirsher  *
17644570b8SJeff Kirsher  * cnetdevice: A Sana-II ethernet driver for AmigaOS
18644570b8SJeff Kirsher  *             Written by Bruce Abbott (bhabbott@inhb.co.nz)
19644570b8SJeff Kirsher  *
20644570b8SJeff Kirsher  * ----------------------------------------------------------------------------
21644570b8SJeff Kirsher  *
22644570b8SJeff Kirsher  * This file is subject to the terms and conditions of the GNU General Public
23644570b8SJeff Kirsher  * License.  See the file COPYING in the main directory of the Linux
24644570b8SJeff Kirsher  * distribution for more details.
25644570b8SJeff Kirsher  *
26644570b8SJeff Kirsher  * ----------------------------------------------------------------------------
27644570b8SJeff Kirsher  *
28644570b8SJeff Kirsher  */
29644570b8SJeff Kirsher 
30644570b8SJeff Kirsher 
31644570b8SJeff Kirsher #include <linux/module.h>
32644570b8SJeff Kirsher #include <linux/kernel.h>
33644570b8SJeff Kirsher #include <linux/errno.h>
34644570b8SJeff Kirsher #include <linux/pci.h>
35644570b8SJeff Kirsher #include <linux/init.h>
36644570b8SJeff Kirsher #include <linux/delay.h>
37644570b8SJeff Kirsher #include <linux/netdevice.h>
38644570b8SJeff Kirsher #include <linux/etherdevice.h>
39644570b8SJeff Kirsher #include <linux/interrupt.h>
40644570b8SJeff Kirsher #include <linux/jiffies.h>
41644570b8SJeff Kirsher 
42644570b8SJeff Kirsher #include <asm/io.h>
43644570b8SJeff Kirsher #include <asm/setup.h>
44644570b8SJeff Kirsher #include <asm/amigaints.h>
45644570b8SJeff Kirsher #include <asm/amigahw.h>
46644570b8SJeff Kirsher #include <asm/amigayle.h>
47644570b8SJeff Kirsher #include <asm/amipcmcia.h>
48644570b8SJeff Kirsher 
49644570b8SJeff Kirsher #include "8390.h"
50644570b8SJeff Kirsher 
51644570b8SJeff Kirsher /* ---- No user-serviceable parts below ---- */
52644570b8SJeff Kirsher 
53644570b8SJeff Kirsher #define DRV_NAME "apne"
54644570b8SJeff Kirsher 
55644570b8SJeff Kirsher #define NE_BASE	 (dev->base_addr)
56644570b8SJeff Kirsher #define NE_CMD	 		0x00
57644570b8SJeff Kirsher #define NE_DATAPORT		0x10            /* NatSemi-defined port window offset. */
58644570b8SJeff Kirsher #define NE_RESET		0x1f            /* Issue a read to reset, a write to clear. */
59644570b8SJeff Kirsher #define NE_IO_EXTENT	        0x20
60644570b8SJeff Kirsher 
61644570b8SJeff Kirsher #define NE_EN0_ISR		0x07
62644570b8SJeff Kirsher #define NE_EN0_DCFG		0x0e
63644570b8SJeff Kirsher 
64644570b8SJeff Kirsher #define NE_EN0_RSARLO	        0x08
65644570b8SJeff Kirsher #define NE_EN0_RSARHI	        0x09
66644570b8SJeff Kirsher #define NE_EN0_RCNTLO	        0x0a
67644570b8SJeff Kirsher #define NE_EN0_RXCR		0x0c
68644570b8SJeff Kirsher #define NE_EN0_TXCR		0x0d
69644570b8SJeff Kirsher #define NE_EN0_RCNTHI	        0x0b
70644570b8SJeff Kirsher #define NE_EN0_IMR		0x0f
71644570b8SJeff Kirsher 
72644570b8SJeff Kirsher #define NE1SM_START_PG	0x20	/* First page of TX buffer */
73644570b8SJeff Kirsher #define NE1SM_STOP_PG 	0x40	/* Last page +1 of RX ring */
74644570b8SJeff Kirsher #define NESM_START_PG	0x40	/* First page of TX buffer */
75644570b8SJeff Kirsher #define NESM_STOP_PG	0x80	/* Last page +1 of RX ring */
76644570b8SJeff Kirsher 
77644570b8SJeff Kirsher 
78644570b8SJeff Kirsher struct net_device * __init apne_probe(int unit);
79644570b8SJeff Kirsher static int apne_probe1(struct net_device *dev, int ioaddr);
80644570b8SJeff Kirsher 
81644570b8SJeff Kirsher static void apne_reset_8390(struct net_device *dev);
82644570b8SJeff Kirsher static void apne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
83644570b8SJeff Kirsher 			  int ring_page);
84644570b8SJeff Kirsher static void apne_block_input(struct net_device *dev, int count,
85644570b8SJeff Kirsher 								struct sk_buff *skb, int ring_offset);
86644570b8SJeff Kirsher static void apne_block_output(struct net_device *dev, const int count,
87644570b8SJeff Kirsher 							const unsigned char *buf, const int start_page);
88644570b8SJeff Kirsher static irqreturn_t apne_interrupt(int irq, void *dev_id);
89644570b8SJeff Kirsher 
90644570b8SJeff Kirsher static int init_pcmcia(void);
91644570b8SJeff Kirsher 
92644570b8SJeff Kirsher /* IO base address used for nic */
93644570b8SJeff Kirsher 
94644570b8SJeff Kirsher #define IOBASE 0x300
95644570b8SJeff Kirsher 
96644570b8SJeff Kirsher /*
97644570b8SJeff Kirsher    use MANUAL_CONFIG and MANUAL_OFFSET for enabling IO by hand
98644570b8SJeff Kirsher    you can find the values to use by looking at the cnet.device
99644570b8SJeff Kirsher    config file example (the default values are for the CNET40BC card)
100644570b8SJeff Kirsher */
101644570b8SJeff Kirsher 
102644570b8SJeff Kirsher /*
103644570b8SJeff Kirsher #define MANUAL_CONFIG 0x20
104644570b8SJeff Kirsher #define MANUAL_OFFSET 0x3f8
105644570b8SJeff Kirsher 
106644570b8SJeff Kirsher #define MANUAL_HWADDR0 0x00
107644570b8SJeff Kirsher #define MANUAL_HWADDR1 0x12
108644570b8SJeff Kirsher #define MANUAL_HWADDR2 0x34
109644570b8SJeff Kirsher #define MANUAL_HWADDR3 0x56
110644570b8SJeff Kirsher #define MANUAL_HWADDR4 0x78
111644570b8SJeff Kirsher #define MANUAL_HWADDR5 0x9a
112644570b8SJeff Kirsher */
113644570b8SJeff Kirsher 
114644570b8SJeff Kirsher static const char version[] =
115644570b8SJeff Kirsher     "apne.c:v1.1 7/10/98 Alain Malek (Alain.Malek@cryogen.ch)\n";
116644570b8SJeff Kirsher 
117644570b8SJeff Kirsher static int apne_owned;	/* signal if card already owned */
118644570b8SJeff Kirsher 
119c45f812fSMatthew Whitehead static u32 apne_msg_enable;
120c45f812fSMatthew Whitehead module_param_named(msg_enable, apne_msg_enable, uint, (S_IRUSR|S_IRGRP|S_IROTH));
121c45f812fSMatthew Whitehead MODULE_PARM_DESC(msg_enable, "Debug message level (see linux/netdevice.h for bitmap)");
122c45f812fSMatthew Whitehead 
123644570b8SJeff Kirsher struct net_device * __init apne_probe(int unit)
124644570b8SJeff Kirsher {
125644570b8SJeff Kirsher 	struct net_device *dev;
126c45f812fSMatthew Whitehead 	struct ei_device *ei_local;
127c45f812fSMatthew Whitehead 
128644570b8SJeff Kirsher #ifndef MANUAL_CONFIG
129644570b8SJeff Kirsher 	char tuple[8];
130644570b8SJeff Kirsher #endif
131644570b8SJeff Kirsher 	int err;
132644570b8SJeff Kirsher 
133644570b8SJeff Kirsher 	if (!MACH_IS_AMIGA)
134644570b8SJeff Kirsher 		return ERR_PTR(-ENODEV);
135644570b8SJeff Kirsher 
136644570b8SJeff Kirsher 	if (apne_owned)
137644570b8SJeff Kirsher 		return ERR_PTR(-ENODEV);
138644570b8SJeff Kirsher 
139644570b8SJeff Kirsher 	if ( !(AMIGAHW_PRESENT(PCMCIA)) )
140644570b8SJeff Kirsher 		return ERR_PTR(-ENODEV);
141644570b8SJeff Kirsher 
142c45f812fSMatthew Whitehead 	pr_info("Looking for PCMCIA ethernet card : ");
143644570b8SJeff Kirsher 
144644570b8SJeff Kirsher 	/* check if a card is inserted */
145644570b8SJeff Kirsher 	if (!(PCMCIA_INSERTED)) {
146c45f812fSMatthew Whitehead 		pr_cont("NO PCMCIA card inserted\n");
147644570b8SJeff Kirsher 		return ERR_PTR(-ENODEV);
148644570b8SJeff Kirsher 	}
149644570b8SJeff Kirsher 
150644570b8SJeff Kirsher 	dev = alloc_ei_netdev();
151644570b8SJeff Kirsher 	if (!dev)
152644570b8SJeff Kirsher 		return ERR_PTR(-ENOMEM);
153644570b8SJeff Kirsher 	if (unit >= 0) {
154644570b8SJeff Kirsher 		sprintf(dev->name, "eth%d", unit);
155644570b8SJeff Kirsher 		netdev_boot_setup_check(dev);
156644570b8SJeff Kirsher 	}
157c45f812fSMatthew Whitehead 	ei_local = netdev_priv(dev);
158c45f812fSMatthew Whitehead 	ei_local->msg_enable = apne_msg_enable;
159644570b8SJeff Kirsher 
160644570b8SJeff Kirsher 	/* disable pcmcia irq for readtuple */
161644570b8SJeff Kirsher 	pcmcia_disable_irq();
162644570b8SJeff Kirsher 
163644570b8SJeff Kirsher #ifndef MANUAL_CONFIG
164644570b8SJeff Kirsher 	if ((pcmcia_copy_tuple(CISTPL_FUNCID, tuple, 8) < 3) ||
165644570b8SJeff Kirsher 		(tuple[2] != CISTPL_FUNCID_NETWORK)) {
166c45f812fSMatthew Whitehead 		pr_cont("not an ethernet card\n");
167644570b8SJeff Kirsher 		/* XXX: shouldn't we re-enable irq here? */
168644570b8SJeff Kirsher 		free_netdev(dev);
169644570b8SJeff Kirsher 		return ERR_PTR(-ENODEV);
170644570b8SJeff Kirsher 	}
171644570b8SJeff Kirsher #endif
172644570b8SJeff Kirsher 
173c45f812fSMatthew Whitehead 	pr_cont("ethernet PCMCIA card inserted\n");
174644570b8SJeff Kirsher 
175644570b8SJeff Kirsher 	if (!init_pcmcia()) {
176644570b8SJeff Kirsher 		/* XXX: shouldn't we re-enable irq here? */
177644570b8SJeff Kirsher 		free_netdev(dev);
178644570b8SJeff Kirsher 		return ERR_PTR(-ENODEV);
179644570b8SJeff Kirsher 	}
180644570b8SJeff Kirsher 
181644570b8SJeff Kirsher 	if (!request_region(IOBASE, 0x20, DRV_NAME)) {
182644570b8SJeff Kirsher 		free_netdev(dev);
183644570b8SJeff Kirsher 		return ERR_PTR(-EBUSY);
184644570b8SJeff Kirsher 	}
185644570b8SJeff Kirsher 
186644570b8SJeff Kirsher 	err = apne_probe1(dev, IOBASE);
187644570b8SJeff Kirsher 	if (err) {
188644570b8SJeff Kirsher 		release_region(IOBASE, 0x20);
189644570b8SJeff Kirsher 		free_netdev(dev);
190644570b8SJeff Kirsher 		return ERR_PTR(err);
191644570b8SJeff Kirsher 	}
192644570b8SJeff Kirsher 	err = register_netdev(dev);
193644570b8SJeff Kirsher 	if (!err)
194644570b8SJeff Kirsher 		return dev;
195644570b8SJeff Kirsher 
196644570b8SJeff Kirsher 	pcmcia_disable_irq();
197644570b8SJeff Kirsher 	free_irq(IRQ_AMIGA_PORTS, dev);
198644570b8SJeff Kirsher 	pcmcia_reset();
199644570b8SJeff Kirsher 	release_region(IOBASE, 0x20);
200644570b8SJeff Kirsher 	free_netdev(dev);
201644570b8SJeff Kirsher 	return ERR_PTR(err);
202644570b8SJeff Kirsher }
203644570b8SJeff Kirsher 
204644570b8SJeff Kirsher static int __init apne_probe1(struct net_device *dev, int ioaddr)
205644570b8SJeff Kirsher {
206644570b8SJeff Kirsher     int i;
207644570b8SJeff Kirsher     unsigned char SA_prom[32];
208644570b8SJeff Kirsher     int wordlength = 2;
209644570b8SJeff Kirsher     const char *name = NULL;
210644570b8SJeff Kirsher     int start_page, stop_page;
211644570b8SJeff Kirsher #ifndef MANUAL_HWADDR0
212644570b8SJeff Kirsher     int neX000, ctron;
213644570b8SJeff Kirsher #endif
214644570b8SJeff Kirsher     static unsigned version_printed;
215c45f812fSMatthew Whitehead     struct ei_device *ei_local = netdev_priv(dev);
216644570b8SJeff Kirsher 
217c45f812fSMatthew Whitehead     if ((apne_msg_enable & NETIF_MSG_DRV) && (version_printed++ == 0))
218c45f812fSMatthew Whitehead 		netdev_info(dev, version);
219644570b8SJeff Kirsher 
220c45f812fSMatthew Whitehead     netdev_info(dev, "PCMCIA NE*000 ethercard probe");
221644570b8SJeff Kirsher 
222644570b8SJeff Kirsher     /* Reset card. Who knows what dain-bramaged state it was left in. */
223644570b8SJeff Kirsher     {	unsigned long reset_start_time = jiffies;
224644570b8SJeff Kirsher 
225644570b8SJeff Kirsher 	outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET);
226644570b8SJeff Kirsher 
227644570b8SJeff Kirsher 	while ((inb(ioaddr + NE_EN0_ISR) & ENISR_RESET) == 0)
228644570b8SJeff Kirsher 		if (time_after(jiffies, reset_start_time + 2*HZ/100)) {
229c45f812fSMatthew Whitehead 			pr_cont(" not found (no reset ack).\n");
230644570b8SJeff Kirsher 			return -ENODEV;
231644570b8SJeff Kirsher 		}
232644570b8SJeff Kirsher 
233644570b8SJeff Kirsher 	outb(0xff, ioaddr + NE_EN0_ISR);		/* Ack all intr. */
234644570b8SJeff Kirsher     }
235644570b8SJeff Kirsher 
236644570b8SJeff Kirsher #ifndef MANUAL_HWADDR0
237644570b8SJeff Kirsher 
238644570b8SJeff Kirsher     /* Read the 16 bytes of station address PROM.
239644570b8SJeff Kirsher        We must first initialize registers, similar to NS8390_init(eifdev, 0).
240644570b8SJeff Kirsher        We can't reliably read the SAPROM address without this.
241644570b8SJeff Kirsher        (I learned the hard way!). */
242644570b8SJeff Kirsher     {
243644570b8SJeff Kirsher 	struct {unsigned long value, offset; } program_seq[] = {
244644570b8SJeff Kirsher 	    {E8390_NODMA+E8390_PAGE0+E8390_STOP, NE_CMD}, /* Select page 0*/
245644570b8SJeff Kirsher 	    {0x48,	NE_EN0_DCFG},	/* Set byte-wide (0x48) access. */
246644570b8SJeff Kirsher 	    {0x00,	NE_EN0_RCNTLO},	/* Clear the count regs. */
247644570b8SJeff Kirsher 	    {0x00,	NE_EN0_RCNTHI},
248644570b8SJeff Kirsher 	    {0x00,	NE_EN0_IMR},	/* Mask completion irq. */
249644570b8SJeff Kirsher 	    {0xFF,	NE_EN0_ISR},
250644570b8SJeff Kirsher 	    {E8390_RXOFF, NE_EN0_RXCR},	/* 0x20  Set to monitor */
251644570b8SJeff Kirsher 	    {E8390_TXOFF, NE_EN0_TXCR},	/* 0x02  and loopback mode. */
252644570b8SJeff Kirsher 	    {32,	NE_EN0_RCNTLO},
253644570b8SJeff Kirsher 	    {0x00,	NE_EN0_RCNTHI},
254644570b8SJeff Kirsher 	    {0x00,	NE_EN0_RSARLO},	/* DMA starting at 0x0000. */
255644570b8SJeff Kirsher 	    {0x00,	NE_EN0_RSARHI},
256644570b8SJeff Kirsher 	    {E8390_RREAD+E8390_START, NE_CMD},
257644570b8SJeff Kirsher 	};
258644570b8SJeff Kirsher 	for (i = 0; i < ARRAY_SIZE(program_seq); i++) {
259644570b8SJeff Kirsher 	    outb(program_seq[i].value, ioaddr + program_seq[i].offset);
260644570b8SJeff Kirsher 	}
261644570b8SJeff Kirsher 
262644570b8SJeff Kirsher     }
263644570b8SJeff Kirsher     for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) {
264644570b8SJeff Kirsher 	SA_prom[i] = inb(ioaddr + NE_DATAPORT);
265644570b8SJeff Kirsher 	SA_prom[i+1] = inb(ioaddr + NE_DATAPORT);
266644570b8SJeff Kirsher 	if (SA_prom[i] != SA_prom[i+1])
267644570b8SJeff Kirsher 	    wordlength = 1;
268644570b8SJeff Kirsher     }
269644570b8SJeff Kirsher 
270644570b8SJeff Kirsher     /*	At this point, wordlength *only* tells us if the SA_prom is doubled
271644570b8SJeff Kirsher 	up or not because some broken PCI cards don't respect the byte-wide
272644570b8SJeff Kirsher 	request in program_seq above, and hence don't have doubled up values.
273644570b8SJeff Kirsher 	These broken cards would otherwise be detected as an ne1000.  */
274644570b8SJeff Kirsher 
275644570b8SJeff Kirsher     if (wordlength == 2)
276644570b8SJeff Kirsher 	for (i = 0; i < 16; i++)
277644570b8SJeff Kirsher 		SA_prom[i] = SA_prom[i+i];
278644570b8SJeff Kirsher 
279644570b8SJeff Kirsher     if (wordlength == 2) {
280644570b8SJeff Kirsher 	/* We must set the 8390 for word mode. */
281644570b8SJeff Kirsher 	outb(0x49, ioaddr + NE_EN0_DCFG);
282644570b8SJeff Kirsher 	start_page = NESM_START_PG;
283644570b8SJeff Kirsher 	stop_page = NESM_STOP_PG;
284644570b8SJeff Kirsher     } else {
285644570b8SJeff Kirsher 	start_page = NE1SM_START_PG;
286644570b8SJeff Kirsher 	stop_page = NE1SM_STOP_PG;
287644570b8SJeff Kirsher     }
288644570b8SJeff Kirsher 
289644570b8SJeff Kirsher     neX000 = (SA_prom[14] == 0x57  &&  SA_prom[15] == 0x57);
290644570b8SJeff Kirsher     ctron =  (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d);
291644570b8SJeff Kirsher 
292644570b8SJeff Kirsher     /* Set up the rest of the parameters. */
293644570b8SJeff Kirsher     if (neX000) {
294644570b8SJeff Kirsher 	name = (wordlength == 2) ? "NE2000" : "NE1000";
295644570b8SJeff Kirsher     } else if (ctron) {
296644570b8SJeff Kirsher 	name = (wordlength == 2) ? "Ctron-8" : "Ctron-16";
297644570b8SJeff Kirsher 	start_page = 0x01;
298644570b8SJeff Kirsher 	stop_page = (wordlength == 2) ? 0x40 : 0x20;
299644570b8SJeff Kirsher     } else {
300c45f812fSMatthew Whitehead 	pr_cont(" not found.\n");
301644570b8SJeff Kirsher 	return -ENXIO;
302644570b8SJeff Kirsher 
303644570b8SJeff Kirsher     }
304644570b8SJeff Kirsher 
305644570b8SJeff Kirsher #else
306644570b8SJeff Kirsher     wordlength = 2;
307644570b8SJeff Kirsher     /* We must set the 8390 for word mode. */
308644570b8SJeff Kirsher     outb(0x49, ioaddr + NE_EN0_DCFG);
309644570b8SJeff Kirsher     start_page = NESM_START_PG;
310644570b8SJeff Kirsher     stop_page = NESM_STOP_PG;
311644570b8SJeff Kirsher 
312644570b8SJeff Kirsher     SA_prom[0] = MANUAL_HWADDR0;
313644570b8SJeff Kirsher     SA_prom[1] = MANUAL_HWADDR1;
314644570b8SJeff Kirsher     SA_prom[2] = MANUAL_HWADDR2;
315644570b8SJeff Kirsher     SA_prom[3] = MANUAL_HWADDR3;
316644570b8SJeff Kirsher     SA_prom[4] = MANUAL_HWADDR4;
317644570b8SJeff Kirsher     SA_prom[5] = MANUAL_HWADDR5;
318644570b8SJeff Kirsher     name = "NE2000";
319644570b8SJeff Kirsher #endif
320644570b8SJeff Kirsher 
321644570b8SJeff Kirsher     dev->base_addr = ioaddr;
322644570b8SJeff Kirsher     dev->irq = IRQ_AMIGA_PORTS;
323644570b8SJeff Kirsher     dev->netdev_ops = &ei_netdev_ops;
324644570b8SJeff Kirsher 
325644570b8SJeff Kirsher     /* Install the Interrupt handler */
326644570b8SJeff Kirsher     i = request_irq(dev->irq, apne_interrupt, IRQF_SHARED, DRV_NAME, dev);
327644570b8SJeff Kirsher     if (i) return i;
328644570b8SJeff Kirsher 
329104bf3fbSJoe Perches     for (i = 0; i < ETH_ALEN; i++)
330644570b8SJeff Kirsher 	dev->dev_addr[i] = SA_prom[i];
331644570b8SJeff Kirsher 
332c45f812fSMatthew Whitehead     pr_cont(" %pM\n", dev->dev_addr);
333644570b8SJeff Kirsher 
334c45f812fSMatthew Whitehead     netdev_info(dev, "%s found.\n", name);
335644570b8SJeff Kirsher 
336644570b8SJeff Kirsher     ei_status.name = name;
337644570b8SJeff Kirsher     ei_status.tx_start_page = start_page;
338644570b8SJeff Kirsher     ei_status.stop_page = stop_page;
339644570b8SJeff Kirsher     ei_status.word16 = (wordlength == 2);
340644570b8SJeff Kirsher 
341644570b8SJeff Kirsher     ei_status.rx_start_page = start_page + TX_PAGES;
342644570b8SJeff Kirsher 
343644570b8SJeff Kirsher     ei_status.reset_8390 = &apne_reset_8390;
344644570b8SJeff Kirsher     ei_status.block_input = &apne_block_input;
345644570b8SJeff Kirsher     ei_status.block_output = &apne_block_output;
346644570b8SJeff Kirsher     ei_status.get_8390_hdr = &apne_get_8390_hdr;
347644570b8SJeff Kirsher 
348644570b8SJeff Kirsher     NS8390_init(dev, 0);
349644570b8SJeff Kirsher 
350644570b8SJeff Kirsher     pcmcia_ack_int(pcmcia_get_intreq());		/* ack PCMCIA int req */
351644570b8SJeff Kirsher     pcmcia_enable_irq();
352644570b8SJeff Kirsher 
353644570b8SJeff Kirsher     apne_owned = 1;
354644570b8SJeff Kirsher 
355644570b8SJeff Kirsher     return 0;
356644570b8SJeff Kirsher }
357644570b8SJeff Kirsher 
358644570b8SJeff Kirsher /* Hard reset the card.  This used to pause for the same period that a
359644570b8SJeff Kirsher    8390 reset command required, but that shouldn't be necessary. */
360644570b8SJeff Kirsher static void
361644570b8SJeff Kirsher apne_reset_8390(struct net_device *dev)
362644570b8SJeff Kirsher {
363644570b8SJeff Kirsher     unsigned long reset_start_time = jiffies;
364c45f812fSMatthew Whitehead     struct ei_device *ei_local = netdev_priv(dev);
365644570b8SJeff Kirsher 
366644570b8SJeff Kirsher     init_pcmcia();
367644570b8SJeff Kirsher 
368c45f812fSMatthew Whitehead     netif_dbg(ei_local, hw, dev, "resetting the 8390 t=%ld...\n", jiffies);
369644570b8SJeff Kirsher 
370644570b8SJeff Kirsher     outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET);
371644570b8SJeff Kirsher 
372644570b8SJeff Kirsher     ei_status.txing = 0;
373644570b8SJeff Kirsher     ei_status.dmaing = 0;
374644570b8SJeff Kirsher 
375644570b8SJeff Kirsher     /* This check _should_not_ be necessary, omit eventually. */
376644570b8SJeff Kirsher     while ((inb(NE_BASE+NE_EN0_ISR) & ENISR_RESET) == 0)
377644570b8SJeff Kirsher 	if (time_after(jiffies, reset_start_time + 2*HZ/100)) {
378c45f812fSMatthew Whitehead 		netdev_err(dev, "ne_reset_8390() did not complete.\n");
379644570b8SJeff Kirsher 		break;
380644570b8SJeff Kirsher 	}
381644570b8SJeff Kirsher     outb(ENISR_RESET, NE_BASE + NE_EN0_ISR);	/* Ack intr. */
382644570b8SJeff Kirsher }
383644570b8SJeff Kirsher 
384644570b8SJeff Kirsher /* Grab the 8390 specific header. Similar to the block_input routine, but
385644570b8SJeff Kirsher    we don't need to be concerned with ring wrap as the header will be at
386644570b8SJeff Kirsher    the start of a page, so we optimize accordingly. */
387644570b8SJeff Kirsher 
388644570b8SJeff Kirsher static void
389644570b8SJeff Kirsher apne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
390644570b8SJeff Kirsher {
391644570b8SJeff Kirsher 
392644570b8SJeff Kirsher     int nic_base = dev->base_addr;
393644570b8SJeff Kirsher     int cnt;
394644570b8SJeff Kirsher     char *ptrc;
395644570b8SJeff Kirsher     short *ptrs;
396644570b8SJeff Kirsher 
397644570b8SJeff Kirsher     /* This *shouldn't* happen. If it does, it's the last thing you'll see */
398644570b8SJeff Kirsher     if (ei_status.dmaing) {
399c45f812fSMatthew Whitehead 	netdev_err(dev, "DMAing conflict in ne_get_8390_hdr "
400644570b8SJeff Kirsher 		   "[DMAstat:%d][irqlock:%d][intr:%d].\n",
401c45f812fSMatthew Whitehead 		   ei_status.dmaing, ei_status.irqlock, dev->irq);
402644570b8SJeff Kirsher 	return;
403644570b8SJeff Kirsher     }
404644570b8SJeff Kirsher 
405644570b8SJeff Kirsher     ei_status.dmaing |= 0x01;
406644570b8SJeff Kirsher     outb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
407644570b8SJeff Kirsher     outb(ENISR_RDC, nic_base + NE_EN0_ISR);
408644570b8SJeff Kirsher     outb(sizeof(struct e8390_pkt_hdr), nic_base + NE_EN0_RCNTLO);
409644570b8SJeff Kirsher     outb(0, nic_base + NE_EN0_RCNTHI);
410644570b8SJeff Kirsher     outb(0, nic_base + NE_EN0_RSARLO);		/* On page boundary */
411644570b8SJeff Kirsher     outb(ring_page, nic_base + NE_EN0_RSARHI);
412644570b8SJeff Kirsher     outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
413644570b8SJeff Kirsher 
414644570b8SJeff Kirsher     if (ei_status.word16) {
415644570b8SJeff Kirsher         ptrs = (short*)hdr;
416644570b8SJeff Kirsher         for(cnt = 0; cnt < (sizeof(struct e8390_pkt_hdr)>>1); cnt++)
417644570b8SJeff Kirsher             *ptrs++ = inw(NE_BASE + NE_DATAPORT);
418644570b8SJeff Kirsher     } else {
419644570b8SJeff Kirsher         ptrc = (char*)hdr;
420644570b8SJeff Kirsher         for(cnt = 0; cnt < sizeof(struct e8390_pkt_hdr); cnt++)
421644570b8SJeff Kirsher             *ptrc++ = inb(NE_BASE + NE_DATAPORT);
422644570b8SJeff Kirsher     }
423644570b8SJeff Kirsher 
424644570b8SJeff Kirsher     outb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
425644570b8SJeff Kirsher     ei_status.dmaing &= ~0x01;
426644570b8SJeff Kirsher 
427644570b8SJeff Kirsher     le16_to_cpus(&hdr->count);
428644570b8SJeff Kirsher }
429644570b8SJeff Kirsher 
430644570b8SJeff Kirsher /* Block input and output, similar to the Crynwr packet driver.  If you
431644570b8SJeff Kirsher    are porting to a new ethercard, look at the packet driver source for hints.
432644570b8SJeff Kirsher    The NEx000 doesn't share the on-board packet memory -- you have to put
433644570b8SJeff Kirsher    the packet out through the "remote DMA" dataport using outb. */
434644570b8SJeff Kirsher 
435644570b8SJeff Kirsher static void
436644570b8SJeff Kirsher apne_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
437644570b8SJeff Kirsher {
438644570b8SJeff Kirsher     int nic_base = dev->base_addr;
439644570b8SJeff Kirsher     char *buf = skb->data;
440644570b8SJeff Kirsher     char *ptrc;
441644570b8SJeff Kirsher     short *ptrs;
442644570b8SJeff Kirsher     int cnt;
443644570b8SJeff Kirsher 
444644570b8SJeff Kirsher     /* This *shouldn't* happen. If it does, it's the last thing you'll see */
445644570b8SJeff Kirsher     if (ei_status.dmaing) {
446c45f812fSMatthew Whitehead 		netdev_err(dev, "DMAing conflict in ne_block_input "
447644570b8SJeff Kirsher 			   "[DMAstat:%d][irqlock:%d][intr:%d].\n",
448c45f812fSMatthew Whitehead 			   ei_status.dmaing, ei_status.irqlock, dev->irq);
449644570b8SJeff Kirsher 	return;
450644570b8SJeff Kirsher     }
451644570b8SJeff Kirsher     ei_status.dmaing |= 0x01;
452644570b8SJeff Kirsher     outb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
453644570b8SJeff Kirsher     outb(ENISR_RDC, nic_base + NE_EN0_ISR);
454644570b8SJeff Kirsher     outb(count & 0xff, nic_base + NE_EN0_RCNTLO);
455644570b8SJeff Kirsher     outb(count >> 8, nic_base + NE_EN0_RCNTHI);
456644570b8SJeff Kirsher     outb(ring_offset & 0xff, nic_base + NE_EN0_RSARLO);
457644570b8SJeff Kirsher     outb(ring_offset >> 8, nic_base + NE_EN0_RSARHI);
458644570b8SJeff Kirsher     outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
459644570b8SJeff Kirsher     if (ei_status.word16) {
460644570b8SJeff Kirsher       ptrs = (short*)buf;
461644570b8SJeff Kirsher       for (cnt = 0; cnt < (count>>1); cnt++)
462644570b8SJeff Kirsher         *ptrs++ = inw(NE_BASE + NE_DATAPORT);
463644570b8SJeff Kirsher       if (count & 0x01) {
464644570b8SJeff Kirsher 	buf[count-1] = inb(NE_BASE + NE_DATAPORT);
465644570b8SJeff Kirsher       }
466644570b8SJeff Kirsher     } else {
46764699336SJoe Perches       ptrc = buf;
468644570b8SJeff Kirsher       for (cnt = 0; cnt < count; cnt++)
469644570b8SJeff Kirsher         *ptrc++ = inb(NE_BASE + NE_DATAPORT);
470644570b8SJeff Kirsher     }
471644570b8SJeff Kirsher 
472644570b8SJeff Kirsher     outb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
473644570b8SJeff Kirsher     ei_status.dmaing &= ~0x01;
474644570b8SJeff Kirsher }
475644570b8SJeff Kirsher 
476644570b8SJeff Kirsher static void
477644570b8SJeff Kirsher apne_block_output(struct net_device *dev, int count,
478644570b8SJeff Kirsher 		const unsigned char *buf, const int start_page)
479644570b8SJeff Kirsher {
480644570b8SJeff Kirsher     int nic_base = NE_BASE;
481644570b8SJeff Kirsher     unsigned long dma_start;
482644570b8SJeff Kirsher     char *ptrc;
483644570b8SJeff Kirsher     short *ptrs;
484644570b8SJeff Kirsher     int cnt;
485644570b8SJeff Kirsher 
486644570b8SJeff Kirsher     /* Round the count up for word writes.  Do we need to do this?
487644570b8SJeff Kirsher        What effect will an odd byte count have on the 8390?
488644570b8SJeff Kirsher        I should check someday. */
489644570b8SJeff Kirsher     if (ei_status.word16 && (count & 0x01))
490644570b8SJeff Kirsher       count++;
491644570b8SJeff Kirsher 
492644570b8SJeff Kirsher     /* This *shouldn't* happen. If it does, it's the last thing you'll see */
493644570b8SJeff Kirsher     if (ei_status.dmaing) {
494c45f812fSMatthew Whitehead 		netdev_err(dev, "DMAing conflict in ne_block_output."
495644570b8SJeff Kirsher 			   "[DMAstat:%d][irqlock:%d][intr:%d]\n",
496c45f812fSMatthew Whitehead 			   ei_status.dmaing, ei_status.irqlock, dev->irq);
497644570b8SJeff Kirsher 	return;
498644570b8SJeff Kirsher     }
499644570b8SJeff Kirsher     ei_status.dmaing |= 0x01;
500644570b8SJeff Kirsher     /* We should already be in page 0, but to be safe... */
501644570b8SJeff Kirsher     outb(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD);
502644570b8SJeff Kirsher 
503644570b8SJeff Kirsher     outb(ENISR_RDC, nic_base + NE_EN0_ISR);
504644570b8SJeff Kirsher 
505644570b8SJeff Kirsher    /* Now the normal output. */
506644570b8SJeff Kirsher     outb(count & 0xff, nic_base + NE_EN0_RCNTLO);
507644570b8SJeff Kirsher     outb(count >> 8,   nic_base + NE_EN0_RCNTHI);
508644570b8SJeff Kirsher     outb(0x00, nic_base + NE_EN0_RSARLO);
509644570b8SJeff Kirsher     outb(start_page, nic_base + NE_EN0_RSARHI);
510644570b8SJeff Kirsher 
511644570b8SJeff Kirsher     outb(E8390_RWRITE+E8390_START, nic_base + NE_CMD);
512644570b8SJeff Kirsher     if (ei_status.word16) {
513644570b8SJeff Kirsher         ptrs = (short*)buf;
514644570b8SJeff Kirsher         for (cnt = 0; cnt < count>>1; cnt++)
515644570b8SJeff Kirsher             outw(*ptrs++, NE_BASE+NE_DATAPORT);
516644570b8SJeff Kirsher     } else {
517644570b8SJeff Kirsher         ptrc = (char*)buf;
518644570b8SJeff Kirsher         for (cnt = 0; cnt < count; cnt++)
519644570b8SJeff Kirsher 	    outb(*ptrc++, NE_BASE + NE_DATAPORT);
520644570b8SJeff Kirsher     }
521644570b8SJeff Kirsher 
522644570b8SJeff Kirsher     dma_start = jiffies;
523644570b8SJeff Kirsher 
524644570b8SJeff Kirsher     while ((inb(NE_BASE + NE_EN0_ISR) & ENISR_RDC) == 0)
525644570b8SJeff Kirsher 	if (time_after(jiffies, dma_start + 2*HZ/100)) {	/* 20ms */
526c45f812fSMatthew Whitehead 		netdev_warn(dev, "timeout waiting for Tx RDC.\n");
527644570b8SJeff Kirsher 		apne_reset_8390(dev);
528644570b8SJeff Kirsher 		NS8390_init(dev,1);
529644570b8SJeff Kirsher 		break;
530644570b8SJeff Kirsher 	}
531644570b8SJeff Kirsher 
532644570b8SJeff Kirsher     outb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
533644570b8SJeff Kirsher     ei_status.dmaing &= ~0x01;
534644570b8SJeff Kirsher }
535644570b8SJeff Kirsher 
536644570b8SJeff Kirsher static irqreturn_t apne_interrupt(int irq, void *dev_id)
537644570b8SJeff Kirsher {
538644570b8SJeff Kirsher     unsigned char pcmcia_intreq;
539644570b8SJeff Kirsher 
540644570b8SJeff Kirsher     if (!(gayle.inten & GAYLE_IRQ_IRQ))
541644570b8SJeff Kirsher         return IRQ_NONE;
542644570b8SJeff Kirsher 
543644570b8SJeff Kirsher     pcmcia_intreq = pcmcia_get_intreq();
544644570b8SJeff Kirsher 
545644570b8SJeff Kirsher     if (!(pcmcia_intreq & GAYLE_IRQ_IRQ)) {
546644570b8SJeff Kirsher         pcmcia_ack_int(pcmcia_intreq);
547644570b8SJeff Kirsher         return IRQ_NONE;
548644570b8SJeff Kirsher     }
549c45f812fSMatthew Whitehead     if (apne_msg_enable & NETIF_MSG_INTR)
550c45f812fSMatthew Whitehead 	pr_debug("pcmcia intreq = %x\n", pcmcia_intreq);
551644570b8SJeff Kirsher     pcmcia_disable_irq();			/* to get rid of the sti() within ei_interrupt */
552644570b8SJeff Kirsher     ei_interrupt(irq, dev_id);
553644570b8SJeff Kirsher     pcmcia_ack_int(pcmcia_get_intreq());
554644570b8SJeff Kirsher     pcmcia_enable_irq();
555644570b8SJeff Kirsher     return IRQ_HANDLED;
556644570b8SJeff Kirsher }
557644570b8SJeff Kirsher 
558644570b8SJeff Kirsher #ifdef MODULE
559644570b8SJeff Kirsher static struct net_device *apne_dev;
560644570b8SJeff Kirsher 
561644570b8SJeff Kirsher static int __init apne_module_init(void)
562644570b8SJeff Kirsher {
563644570b8SJeff Kirsher 	apne_dev = apne_probe(-1);
564644570b8SJeff Kirsher 	if (IS_ERR(apne_dev))
565644570b8SJeff Kirsher 		return PTR_ERR(apne_dev);
566644570b8SJeff Kirsher 	return 0;
567644570b8SJeff Kirsher }
568644570b8SJeff Kirsher 
569644570b8SJeff Kirsher static void __exit apne_module_exit(void)
570644570b8SJeff Kirsher {
571644570b8SJeff Kirsher 	unregister_netdev(apne_dev);
572644570b8SJeff Kirsher 
573644570b8SJeff Kirsher 	pcmcia_disable_irq();
574644570b8SJeff Kirsher 
575644570b8SJeff Kirsher 	free_irq(IRQ_AMIGA_PORTS, apne_dev);
576644570b8SJeff Kirsher 
577644570b8SJeff Kirsher 	pcmcia_reset();
578644570b8SJeff Kirsher 
579644570b8SJeff Kirsher 	release_region(IOBASE, 0x20);
580644570b8SJeff Kirsher 
581644570b8SJeff Kirsher 	free_netdev(apne_dev);
582644570b8SJeff Kirsher }
583644570b8SJeff Kirsher module_init(apne_module_init);
584644570b8SJeff Kirsher module_exit(apne_module_exit);
585644570b8SJeff Kirsher #endif
586644570b8SJeff Kirsher 
587644570b8SJeff Kirsher static int init_pcmcia(void)
588644570b8SJeff Kirsher {
589644570b8SJeff Kirsher 	u_char config;
590644570b8SJeff Kirsher #ifndef MANUAL_CONFIG
591644570b8SJeff Kirsher 	u_char tuple[32];
592644570b8SJeff Kirsher 	int offset_len;
593644570b8SJeff Kirsher #endif
594644570b8SJeff Kirsher 	u_long offset;
595644570b8SJeff Kirsher 
596644570b8SJeff Kirsher 	pcmcia_reset();
597644570b8SJeff Kirsher 	pcmcia_program_voltage(PCMCIA_0V);
598644570b8SJeff Kirsher 	pcmcia_access_speed(PCMCIA_SPEED_250NS);
599644570b8SJeff Kirsher 	pcmcia_write_enable();
600644570b8SJeff Kirsher 
601644570b8SJeff Kirsher #ifdef MANUAL_CONFIG
602644570b8SJeff Kirsher 	config = MANUAL_CONFIG;
603644570b8SJeff Kirsher #else
604644570b8SJeff Kirsher 	/* get and write config byte to enable IO port */
605644570b8SJeff Kirsher 
606644570b8SJeff Kirsher 	if (pcmcia_copy_tuple(CISTPL_CFTABLE_ENTRY, tuple, 32) < 3)
607644570b8SJeff Kirsher 		return 0;
608644570b8SJeff Kirsher 
609644570b8SJeff Kirsher 	config = tuple[2] & 0x3f;
610644570b8SJeff Kirsher #endif
611644570b8SJeff Kirsher #ifdef MANUAL_OFFSET
612644570b8SJeff Kirsher 	offset = MANUAL_OFFSET;
613644570b8SJeff Kirsher #else
614644570b8SJeff Kirsher 	if (pcmcia_copy_tuple(CISTPL_CONFIG, tuple, 32) < 6)
615644570b8SJeff Kirsher 		return 0;
616644570b8SJeff Kirsher 
617644570b8SJeff Kirsher 	offset_len = (tuple[2] & 0x3) + 1;
618644570b8SJeff Kirsher 	offset = 0;
619644570b8SJeff Kirsher 	while(offset_len--) {
620644570b8SJeff Kirsher 		offset = (offset << 8) | tuple[4+offset_len];
621644570b8SJeff Kirsher 	}
622644570b8SJeff Kirsher #endif
623644570b8SJeff Kirsher 
624644570b8SJeff Kirsher 	out_8(GAYLE_ATTRIBUTE+offset, config);
625644570b8SJeff Kirsher 
626644570b8SJeff Kirsher 	return 1;
627644570b8SJeff Kirsher }
628644570b8SJeff Kirsher 
629644570b8SJeff Kirsher MODULE_LICENSE("GPL");
630