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