xref: /OK3568_Linux_fs/kernel/drivers/net/ethernet/8390/apne.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Amiga Linux/68k 8390 based PCMCIA Ethernet Driver for the Amiga 1200
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * (C) Copyright 1997 Alain Malek
5*4882a593Smuzhiyun  *                    (Alain.Malek@cryogen.com)
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * ----------------------------------------------------------------------------
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * This program is based on
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * ne.c:       A general non-shared-memory NS8390 ethernet driver for linux
12*4882a593Smuzhiyun  *             Written 1992-94 by Donald Becker.
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  * 8390.c:     A general NS8390 ethernet driver core for linux.
15*4882a593Smuzhiyun  *             Written 1992-94 by Donald Becker.
16*4882a593Smuzhiyun  *
17*4882a593Smuzhiyun  * cnetdevice: A Sana-II ethernet driver for AmigaOS
18*4882a593Smuzhiyun  *             Written by Bruce Abbott (bhabbott@inhb.co.nz)
19*4882a593Smuzhiyun  *
20*4882a593Smuzhiyun  * ----------------------------------------------------------------------------
21*4882a593Smuzhiyun  *
22*4882a593Smuzhiyun  * This file is subject to the terms and conditions of the GNU General Public
23*4882a593Smuzhiyun  * License.  See the file COPYING in the main directory of the Linux
24*4882a593Smuzhiyun  * distribution for more details.
25*4882a593Smuzhiyun  *
26*4882a593Smuzhiyun  * ----------------------------------------------------------------------------
27*4882a593Smuzhiyun  *
28*4882a593Smuzhiyun  */
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun #include <linux/module.h>
32*4882a593Smuzhiyun #include <linux/kernel.h>
33*4882a593Smuzhiyun #include <linux/errno.h>
34*4882a593Smuzhiyun #include <linux/pci.h>
35*4882a593Smuzhiyun #include <linux/init.h>
36*4882a593Smuzhiyun #include <linux/delay.h>
37*4882a593Smuzhiyun #include <linux/netdevice.h>
38*4882a593Smuzhiyun #include <linux/etherdevice.h>
39*4882a593Smuzhiyun #include <linux/interrupt.h>
40*4882a593Smuzhiyun #include <linux/jiffies.h>
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun #include <asm/io.h>
43*4882a593Smuzhiyun #include <asm/setup.h>
44*4882a593Smuzhiyun #include <asm/amigaints.h>
45*4882a593Smuzhiyun #include <asm/amigahw.h>
46*4882a593Smuzhiyun #include <asm/amigayle.h>
47*4882a593Smuzhiyun #include <asm/amipcmcia.h>
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun #include "8390.h"
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun /* ---- No user-serviceable parts below ---- */
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun #define DRV_NAME "apne"
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun #define NE_BASE	 (dev->base_addr)
56*4882a593Smuzhiyun #define NE_CMD	 		0x00
57*4882a593Smuzhiyun #define NE_DATAPORT		0x10            /* NatSemi-defined port window offset. */
58*4882a593Smuzhiyun #define NE_RESET		0x1f            /* Issue a read to reset, a write to clear. */
59*4882a593Smuzhiyun #define NE_IO_EXTENT	        0x20
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun #define NE_EN0_ISR		0x07
62*4882a593Smuzhiyun #define NE_EN0_DCFG		0x0e
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun #define NE_EN0_RSARLO	        0x08
65*4882a593Smuzhiyun #define NE_EN0_RSARHI	        0x09
66*4882a593Smuzhiyun #define NE_EN0_RCNTLO	        0x0a
67*4882a593Smuzhiyun #define NE_EN0_RXCR		0x0c
68*4882a593Smuzhiyun #define NE_EN0_TXCR		0x0d
69*4882a593Smuzhiyun #define NE_EN0_RCNTHI	        0x0b
70*4882a593Smuzhiyun #define NE_EN0_IMR		0x0f
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun #define NE1SM_START_PG	0x20	/* First page of TX buffer */
73*4882a593Smuzhiyun #define NE1SM_STOP_PG 	0x40	/* Last page +1 of RX ring */
74*4882a593Smuzhiyun #define NESM_START_PG	0x40	/* First page of TX buffer */
75*4882a593Smuzhiyun #define NESM_STOP_PG	0x80	/* Last page +1 of RX ring */
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun struct net_device * __init apne_probe(int unit);
79*4882a593Smuzhiyun static int apne_probe1(struct net_device *dev, int ioaddr);
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun static void apne_reset_8390(struct net_device *dev);
82*4882a593Smuzhiyun static void apne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
83*4882a593Smuzhiyun 			  int ring_page);
84*4882a593Smuzhiyun static void apne_block_input(struct net_device *dev, int count,
85*4882a593Smuzhiyun 								struct sk_buff *skb, int ring_offset);
86*4882a593Smuzhiyun static void apne_block_output(struct net_device *dev, const int count,
87*4882a593Smuzhiyun 							const unsigned char *buf, const int start_page);
88*4882a593Smuzhiyun static irqreturn_t apne_interrupt(int irq, void *dev_id);
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun static int init_pcmcia(void);
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun /* IO base address used for nic */
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun #define IOBASE 0x300
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun /*
97*4882a593Smuzhiyun    use MANUAL_CONFIG and MANUAL_OFFSET for enabling IO by hand
98*4882a593Smuzhiyun    you can find the values to use by looking at the cnet.device
99*4882a593Smuzhiyun    config file example (the default values are for the CNET40BC card)
100*4882a593Smuzhiyun */
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun /*
103*4882a593Smuzhiyun #define MANUAL_CONFIG 0x20
104*4882a593Smuzhiyun #define MANUAL_OFFSET 0x3f8
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun #define MANUAL_HWADDR0 0x00
107*4882a593Smuzhiyun #define MANUAL_HWADDR1 0x12
108*4882a593Smuzhiyun #define MANUAL_HWADDR2 0x34
109*4882a593Smuzhiyun #define MANUAL_HWADDR3 0x56
110*4882a593Smuzhiyun #define MANUAL_HWADDR4 0x78
111*4882a593Smuzhiyun #define MANUAL_HWADDR5 0x9a
112*4882a593Smuzhiyun */
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun static const char version[] =
115*4882a593Smuzhiyun     "apne.c:v1.1 7/10/98 Alain Malek (Alain.Malek@cryogen.ch)\n";
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun static int apne_owned;	/* signal if card already owned */
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun static u32 apne_msg_enable;
120*4882a593Smuzhiyun module_param_named(msg_enable, apne_msg_enable, uint, 0444);
121*4882a593Smuzhiyun MODULE_PARM_DESC(msg_enable, "Debug message level (see linux/netdevice.h for bitmap)");
122*4882a593Smuzhiyun 
apne_probe(int unit)123*4882a593Smuzhiyun struct net_device * __init apne_probe(int unit)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun 	struct net_device *dev;
126*4882a593Smuzhiyun 	struct ei_device *ei_local;
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun #ifndef MANUAL_CONFIG
129*4882a593Smuzhiyun 	char tuple[8];
130*4882a593Smuzhiyun #endif
131*4882a593Smuzhiyun 	int err;
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	if (!MACH_IS_AMIGA)
134*4882a593Smuzhiyun 		return ERR_PTR(-ENODEV);
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	if (apne_owned)
137*4882a593Smuzhiyun 		return ERR_PTR(-ENODEV);
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	if ( !(AMIGAHW_PRESENT(PCMCIA)) )
140*4882a593Smuzhiyun 		return ERR_PTR(-ENODEV);
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	pr_info("Looking for PCMCIA ethernet card : ");
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	/* check if a card is inserted */
145*4882a593Smuzhiyun 	if (!(PCMCIA_INSERTED)) {
146*4882a593Smuzhiyun 		pr_cont("NO PCMCIA card inserted\n");
147*4882a593Smuzhiyun 		return ERR_PTR(-ENODEV);
148*4882a593Smuzhiyun 	}
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	dev = alloc_ei_netdev();
151*4882a593Smuzhiyun 	if (!dev)
152*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
153*4882a593Smuzhiyun 	if (unit >= 0) {
154*4882a593Smuzhiyun 		sprintf(dev->name, "eth%d", unit);
155*4882a593Smuzhiyun 		netdev_boot_setup_check(dev);
156*4882a593Smuzhiyun 	}
157*4882a593Smuzhiyun 	ei_local = netdev_priv(dev);
158*4882a593Smuzhiyun 	ei_local->msg_enable = apne_msg_enable;
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	/* disable pcmcia irq for readtuple */
161*4882a593Smuzhiyun 	pcmcia_disable_irq();
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun #ifndef MANUAL_CONFIG
164*4882a593Smuzhiyun 	if ((pcmcia_copy_tuple(CISTPL_FUNCID, tuple, 8) < 3) ||
165*4882a593Smuzhiyun 		(tuple[2] != CISTPL_FUNCID_NETWORK)) {
166*4882a593Smuzhiyun 		pr_cont("not an ethernet card\n");
167*4882a593Smuzhiyun 		/* XXX: shouldn't we re-enable irq here? */
168*4882a593Smuzhiyun 		free_netdev(dev);
169*4882a593Smuzhiyun 		return ERR_PTR(-ENODEV);
170*4882a593Smuzhiyun 	}
171*4882a593Smuzhiyun #endif
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	pr_cont("ethernet PCMCIA card inserted\n");
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	if (!init_pcmcia()) {
176*4882a593Smuzhiyun 		/* XXX: shouldn't we re-enable irq here? */
177*4882a593Smuzhiyun 		free_netdev(dev);
178*4882a593Smuzhiyun 		return ERR_PTR(-ENODEV);
179*4882a593Smuzhiyun 	}
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	if (!request_region(IOBASE, 0x20, DRV_NAME)) {
182*4882a593Smuzhiyun 		free_netdev(dev);
183*4882a593Smuzhiyun 		return ERR_PTR(-EBUSY);
184*4882a593Smuzhiyun 	}
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	err = apne_probe1(dev, IOBASE);
187*4882a593Smuzhiyun 	if (err) {
188*4882a593Smuzhiyun 		release_region(IOBASE, 0x20);
189*4882a593Smuzhiyun 		free_netdev(dev);
190*4882a593Smuzhiyun 		return ERR_PTR(err);
191*4882a593Smuzhiyun 	}
192*4882a593Smuzhiyun 	err = register_netdev(dev);
193*4882a593Smuzhiyun 	if (!err)
194*4882a593Smuzhiyun 		return dev;
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	pcmcia_disable_irq();
197*4882a593Smuzhiyun 	free_irq(IRQ_AMIGA_PORTS, dev);
198*4882a593Smuzhiyun 	pcmcia_reset();
199*4882a593Smuzhiyun 	release_region(IOBASE, 0x20);
200*4882a593Smuzhiyun 	free_netdev(dev);
201*4882a593Smuzhiyun 	return ERR_PTR(err);
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun 
apne_probe1(struct net_device * dev,int ioaddr)204*4882a593Smuzhiyun static int __init apne_probe1(struct net_device *dev, int ioaddr)
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun     int i;
207*4882a593Smuzhiyun     unsigned char SA_prom[32];
208*4882a593Smuzhiyun     int wordlength = 2;
209*4882a593Smuzhiyun     const char *name = NULL;
210*4882a593Smuzhiyun     int start_page, stop_page;
211*4882a593Smuzhiyun #ifndef MANUAL_HWADDR0
212*4882a593Smuzhiyun     int neX000, ctron;
213*4882a593Smuzhiyun #endif
214*4882a593Smuzhiyun     static unsigned version_printed;
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun     if ((apne_msg_enable & NETIF_MSG_DRV) && (version_printed++ == 0))
217*4882a593Smuzhiyun 		netdev_info(dev, version);
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun     netdev_info(dev, "PCMCIA NE*000 ethercard probe");
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun     /* Reset card. Who knows what dain-bramaged state it was left in. */
222*4882a593Smuzhiyun     {	unsigned long reset_start_time = jiffies;
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET);
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	while ((inb(ioaddr + NE_EN0_ISR) & ENISR_RESET) == 0)
227*4882a593Smuzhiyun 		if (time_after(jiffies, reset_start_time + 2*HZ/100)) {
228*4882a593Smuzhiyun 			pr_cont(" not found (no reset ack).\n");
229*4882a593Smuzhiyun 			return -ENODEV;
230*4882a593Smuzhiyun 		}
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	outb(0xff, ioaddr + NE_EN0_ISR);		/* Ack all intr. */
233*4882a593Smuzhiyun     }
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun #ifndef MANUAL_HWADDR0
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun     /* Read the 16 bytes of station address PROM.
238*4882a593Smuzhiyun        We must first initialize registers, similar to NS8390_init(eifdev, 0).
239*4882a593Smuzhiyun        We can't reliably read the SAPROM address without this.
240*4882a593Smuzhiyun        (I learned the hard way!). */
241*4882a593Smuzhiyun     {
242*4882a593Smuzhiyun 	struct {unsigned long value, offset; } program_seq[] = {
243*4882a593Smuzhiyun 	    {E8390_NODMA+E8390_PAGE0+E8390_STOP, NE_CMD}, /* Select page 0*/
244*4882a593Smuzhiyun 	    {0x48,	NE_EN0_DCFG},	/* Set byte-wide (0x48) access. */
245*4882a593Smuzhiyun 	    {0x00,	NE_EN0_RCNTLO},	/* Clear the count regs. */
246*4882a593Smuzhiyun 	    {0x00,	NE_EN0_RCNTHI},
247*4882a593Smuzhiyun 	    {0x00,	NE_EN0_IMR},	/* Mask completion irq. */
248*4882a593Smuzhiyun 	    {0xFF,	NE_EN0_ISR},
249*4882a593Smuzhiyun 	    {E8390_RXOFF, NE_EN0_RXCR},	/* 0x20  Set to monitor */
250*4882a593Smuzhiyun 	    {E8390_TXOFF, NE_EN0_TXCR},	/* 0x02  and loopback mode. */
251*4882a593Smuzhiyun 	    {32,	NE_EN0_RCNTLO},
252*4882a593Smuzhiyun 	    {0x00,	NE_EN0_RCNTHI},
253*4882a593Smuzhiyun 	    {0x00,	NE_EN0_RSARLO},	/* DMA starting at 0x0000. */
254*4882a593Smuzhiyun 	    {0x00,	NE_EN0_RSARHI},
255*4882a593Smuzhiyun 	    {E8390_RREAD+E8390_START, NE_CMD},
256*4882a593Smuzhiyun 	};
257*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(program_seq); i++) {
258*4882a593Smuzhiyun 	    outb(program_seq[i].value, ioaddr + program_seq[i].offset);
259*4882a593Smuzhiyun 	}
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun     }
262*4882a593Smuzhiyun     for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) {
263*4882a593Smuzhiyun 	SA_prom[i] = inb(ioaddr + NE_DATAPORT);
264*4882a593Smuzhiyun 	SA_prom[i+1] = inb(ioaddr + NE_DATAPORT);
265*4882a593Smuzhiyun 	if (SA_prom[i] != SA_prom[i+1])
266*4882a593Smuzhiyun 	    wordlength = 1;
267*4882a593Smuzhiyun     }
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun     /*	At this point, wordlength *only* tells us if the SA_prom is doubled
270*4882a593Smuzhiyun 	up or not because some broken PCI cards don't respect the byte-wide
271*4882a593Smuzhiyun 	request in program_seq above, and hence don't have doubled up values.
272*4882a593Smuzhiyun 	These broken cards would otherwise be detected as an ne1000.  */
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun     if (wordlength == 2)
275*4882a593Smuzhiyun 	for (i = 0; i < 16; i++)
276*4882a593Smuzhiyun 		SA_prom[i] = SA_prom[i+i];
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun     if (wordlength == 2) {
279*4882a593Smuzhiyun 	/* We must set the 8390 for word mode. */
280*4882a593Smuzhiyun 	outb(0x49, ioaddr + NE_EN0_DCFG);
281*4882a593Smuzhiyun 	start_page = NESM_START_PG;
282*4882a593Smuzhiyun 	stop_page = NESM_STOP_PG;
283*4882a593Smuzhiyun     } else {
284*4882a593Smuzhiyun 	start_page = NE1SM_START_PG;
285*4882a593Smuzhiyun 	stop_page = NE1SM_STOP_PG;
286*4882a593Smuzhiyun     }
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun     neX000 = (SA_prom[14] == 0x57  &&  SA_prom[15] == 0x57);
289*4882a593Smuzhiyun     ctron =  (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d);
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun     /* Set up the rest of the parameters. */
292*4882a593Smuzhiyun     if (neX000) {
293*4882a593Smuzhiyun 	name = (wordlength == 2) ? "NE2000" : "NE1000";
294*4882a593Smuzhiyun     } else if (ctron) {
295*4882a593Smuzhiyun 	name = (wordlength == 2) ? "Ctron-8" : "Ctron-16";
296*4882a593Smuzhiyun 	start_page = 0x01;
297*4882a593Smuzhiyun 	stop_page = (wordlength == 2) ? 0x40 : 0x20;
298*4882a593Smuzhiyun     } else {
299*4882a593Smuzhiyun 	pr_cont(" not found.\n");
300*4882a593Smuzhiyun 	return -ENXIO;
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun     }
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun #else
305*4882a593Smuzhiyun     wordlength = 2;
306*4882a593Smuzhiyun     /* We must set the 8390 for word mode. */
307*4882a593Smuzhiyun     outb(0x49, ioaddr + NE_EN0_DCFG);
308*4882a593Smuzhiyun     start_page = NESM_START_PG;
309*4882a593Smuzhiyun     stop_page = NESM_STOP_PG;
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun     SA_prom[0] = MANUAL_HWADDR0;
312*4882a593Smuzhiyun     SA_prom[1] = MANUAL_HWADDR1;
313*4882a593Smuzhiyun     SA_prom[2] = MANUAL_HWADDR2;
314*4882a593Smuzhiyun     SA_prom[3] = MANUAL_HWADDR3;
315*4882a593Smuzhiyun     SA_prom[4] = MANUAL_HWADDR4;
316*4882a593Smuzhiyun     SA_prom[5] = MANUAL_HWADDR5;
317*4882a593Smuzhiyun     name = "NE2000";
318*4882a593Smuzhiyun #endif
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun     dev->base_addr = ioaddr;
321*4882a593Smuzhiyun     dev->irq = IRQ_AMIGA_PORTS;
322*4882a593Smuzhiyun     dev->netdev_ops = &ei_netdev_ops;
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun     /* Install the Interrupt handler */
325*4882a593Smuzhiyun     i = request_irq(dev->irq, apne_interrupt, IRQF_SHARED, DRV_NAME, dev);
326*4882a593Smuzhiyun     if (i) return i;
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun     for (i = 0; i < ETH_ALEN; i++)
329*4882a593Smuzhiyun 	dev->dev_addr[i] = SA_prom[i];
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun     pr_cont(" %pM\n", dev->dev_addr);
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun     netdev_info(dev, "%s found.\n", name);
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun     ei_status.name = name;
336*4882a593Smuzhiyun     ei_status.tx_start_page = start_page;
337*4882a593Smuzhiyun     ei_status.stop_page = stop_page;
338*4882a593Smuzhiyun     ei_status.word16 = (wordlength == 2);
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun     ei_status.rx_start_page = start_page + TX_PAGES;
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun     ei_status.reset_8390 = &apne_reset_8390;
343*4882a593Smuzhiyun     ei_status.block_input = &apne_block_input;
344*4882a593Smuzhiyun     ei_status.block_output = &apne_block_output;
345*4882a593Smuzhiyun     ei_status.get_8390_hdr = &apne_get_8390_hdr;
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun     NS8390_init(dev, 0);
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun     pcmcia_ack_int(pcmcia_get_intreq());		/* ack PCMCIA int req */
350*4882a593Smuzhiyun     pcmcia_enable_irq();
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun     apne_owned = 1;
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun     return 0;
355*4882a593Smuzhiyun }
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun /* Hard reset the card.  This used to pause for the same period that a
358*4882a593Smuzhiyun    8390 reset command required, but that shouldn't be necessary. */
359*4882a593Smuzhiyun static void
apne_reset_8390(struct net_device * dev)360*4882a593Smuzhiyun apne_reset_8390(struct net_device *dev)
361*4882a593Smuzhiyun {
362*4882a593Smuzhiyun     unsigned long reset_start_time = jiffies;
363*4882a593Smuzhiyun     struct ei_device *ei_local = netdev_priv(dev);
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun     init_pcmcia();
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun     netif_dbg(ei_local, hw, dev, "resetting the 8390 t=%ld...\n", jiffies);
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun     outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET);
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun     ei_status.txing = 0;
372*4882a593Smuzhiyun     ei_status.dmaing = 0;
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun     /* This check _should_not_ be necessary, omit eventually. */
375*4882a593Smuzhiyun     while ((inb(NE_BASE+NE_EN0_ISR) & ENISR_RESET) == 0)
376*4882a593Smuzhiyun 	if (time_after(jiffies, reset_start_time + 2*HZ/100)) {
377*4882a593Smuzhiyun 		netdev_err(dev, "ne_reset_8390() did not complete.\n");
378*4882a593Smuzhiyun 		break;
379*4882a593Smuzhiyun 	}
380*4882a593Smuzhiyun     outb(ENISR_RESET, NE_BASE + NE_EN0_ISR);	/* Ack intr. */
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun /* Grab the 8390 specific header. Similar to the block_input routine, but
384*4882a593Smuzhiyun    we don't need to be concerned with ring wrap as the header will be at
385*4882a593Smuzhiyun    the start of a page, so we optimize accordingly. */
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun static void
apne_get_8390_hdr(struct net_device * dev,struct e8390_pkt_hdr * hdr,int ring_page)388*4882a593Smuzhiyun apne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
389*4882a593Smuzhiyun {
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun     int nic_base = dev->base_addr;
392*4882a593Smuzhiyun     int cnt;
393*4882a593Smuzhiyun     char *ptrc;
394*4882a593Smuzhiyun     short *ptrs;
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun     /* This *shouldn't* happen. If it does, it's the last thing you'll see */
397*4882a593Smuzhiyun     if (ei_status.dmaing) {
398*4882a593Smuzhiyun 	netdev_err(dev, "DMAing conflict in ne_get_8390_hdr "
399*4882a593Smuzhiyun 		   "[DMAstat:%d][irqlock:%d][intr:%d].\n",
400*4882a593Smuzhiyun 		   ei_status.dmaing, ei_status.irqlock, dev->irq);
401*4882a593Smuzhiyun 	return;
402*4882a593Smuzhiyun     }
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun     ei_status.dmaing |= 0x01;
405*4882a593Smuzhiyun     outb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
406*4882a593Smuzhiyun     outb(ENISR_RDC, nic_base + NE_EN0_ISR);
407*4882a593Smuzhiyun     outb(sizeof(struct e8390_pkt_hdr), nic_base + NE_EN0_RCNTLO);
408*4882a593Smuzhiyun     outb(0, nic_base + NE_EN0_RCNTHI);
409*4882a593Smuzhiyun     outb(0, nic_base + NE_EN0_RSARLO);		/* On page boundary */
410*4882a593Smuzhiyun     outb(ring_page, nic_base + NE_EN0_RSARHI);
411*4882a593Smuzhiyun     outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun     if (ei_status.word16) {
414*4882a593Smuzhiyun         ptrs = (short*)hdr;
415*4882a593Smuzhiyun         for(cnt = 0; cnt < (sizeof(struct e8390_pkt_hdr)>>1); cnt++)
416*4882a593Smuzhiyun             *ptrs++ = inw(NE_BASE + NE_DATAPORT);
417*4882a593Smuzhiyun     } else {
418*4882a593Smuzhiyun         ptrc = (char*)hdr;
419*4882a593Smuzhiyun         for(cnt = 0; cnt < sizeof(struct e8390_pkt_hdr); cnt++)
420*4882a593Smuzhiyun             *ptrc++ = inb(NE_BASE + NE_DATAPORT);
421*4882a593Smuzhiyun     }
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun     outb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
424*4882a593Smuzhiyun     ei_status.dmaing &= ~0x01;
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun     le16_to_cpus(&hdr->count);
427*4882a593Smuzhiyun }
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun /* Block input and output, similar to the Crynwr packet driver.  If you
430*4882a593Smuzhiyun    are porting to a new ethercard, look at the packet driver source for hints.
431*4882a593Smuzhiyun    The NEx000 doesn't share the on-board packet memory -- you have to put
432*4882a593Smuzhiyun    the packet out through the "remote DMA" dataport using outb. */
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun static void
apne_block_input(struct net_device * dev,int count,struct sk_buff * skb,int ring_offset)435*4882a593Smuzhiyun apne_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
436*4882a593Smuzhiyun {
437*4882a593Smuzhiyun     int nic_base = dev->base_addr;
438*4882a593Smuzhiyun     char *buf = skb->data;
439*4882a593Smuzhiyun     char *ptrc;
440*4882a593Smuzhiyun     short *ptrs;
441*4882a593Smuzhiyun     int cnt;
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun     /* This *shouldn't* happen. If it does, it's the last thing you'll see */
444*4882a593Smuzhiyun     if (ei_status.dmaing) {
445*4882a593Smuzhiyun 		netdev_err(dev, "DMAing conflict in ne_block_input "
446*4882a593Smuzhiyun 			   "[DMAstat:%d][irqlock:%d][intr:%d].\n",
447*4882a593Smuzhiyun 			   ei_status.dmaing, ei_status.irqlock, dev->irq);
448*4882a593Smuzhiyun 	return;
449*4882a593Smuzhiyun     }
450*4882a593Smuzhiyun     ei_status.dmaing |= 0x01;
451*4882a593Smuzhiyun     outb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
452*4882a593Smuzhiyun     outb(ENISR_RDC, nic_base + NE_EN0_ISR);
453*4882a593Smuzhiyun     outb(count & 0xff, nic_base + NE_EN0_RCNTLO);
454*4882a593Smuzhiyun     outb(count >> 8, nic_base + NE_EN0_RCNTHI);
455*4882a593Smuzhiyun     outb(ring_offset & 0xff, nic_base + NE_EN0_RSARLO);
456*4882a593Smuzhiyun     outb(ring_offset >> 8, nic_base + NE_EN0_RSARHI);
457*4882a593Smuzhiyun     outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
458*4882a593Smuzhiyun     if (ei_status.word16) {
459*4882a593Smuzhiyun       ptrs = (short*)buf;
460*4882a593Smuzhiyun       for (cnt = 0; cnt < (count>>1); cnt++)
461*4882a593Smuzhiyun         *ptrs++ = inw(NE_BASE + NE_DATAPORT);
462*4882a593Smuzhiyun       if (count & 0x01) {
463*4882a593Smuzhiyun 	buf[count-1] = inb(NE_BASE + NE_DATAPORT);
464*4882a593Smuzhiyun       }
465*4882a593Smuzhiyun     } else {
466*4882a593Smuzhiyun       ptrc = buf;
467*4882a593Smuzhiyun       for (cnt = 0; cnt < count; cnt++)
468*4882a593Smuzhiyun         *ptrc++ = inb(NE_BASE + NE_DATAPORT);
469*4882a593Smuzhiyun     }
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun     outb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
472*4882a593Smuzhiyun     ei_status.dmaing &= ~0x01;
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun static void
apne_block_output(struct net_device * dev,int count,const unsigned char * buf,const int start_page)476*4882a593Smuzhiyun apne_block_output(struct net_device *dev, int count,
477*4882a593Smuzhiyun 		const unsigned char *buf, const int start_page)
478*4882a593Smuzhiyun {
479*4882a593Smuzhiyun     int nic_base = NE_BASE;
480*4882a593Smuzhiyun     unsigned long dma_start;
481*4882a593Smuzhiyun     char *ptrc;
482*4882a593Smuzhiyun     short *ptrs;
483*4882a593Smuzhiyun     int cnt;
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun     /* Round the count up for word writes.  Do we need to do this?
486*4882a593Smuzhiyun        What effect will an odd byte count have on the 8390?
487*4882a593Smuzhiyun        I should check someday. */
488*4882a593Smuzhiyun     if (ei_status.word16 && (count & 0x01))
489*4882a593Smuzhiyun       count++;
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun     /* This *shouldn't* happen. If it does, it's the last thing you'll see */
492*4882a593Smuzhiyun     if (ei_status.dmaing) {
493*4882a593Smuzhiyun 		netdev_err(dev, "DMAing conflict in ne_block_output."
494*4882a593Smuzhiyun 			   "[DMAstat:%d][irqlock:%d][intr:%d]\n",
495*4882a593Smuzhiyun 			   ei_status.dmaing, ei_status.irqlock, dev->irq);
496*4882a593Smuzhiyun 	return;
497*4882a593Smuzhiyun     }
498*4882a593Smuzhiyun     ei_status.dmaing |= 0x01;
499*4882a593Smuzhiyun     /* We should already be in page 0, but to be safe... */
500*4882a593Smuzhiyun     outb(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD);
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun     outb(ENISR_RDC, nic_base + NE_EN0_ISR);
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun    /* Now the normal output. */
505*4882a593Smuzhiyun     outb(count & 0xff, nic_base + NE_EN0_RCNTLO);
506*4882a593Smuzhiyun     outb(count >> 8,   nic_base + NE_EN0_RCNTHI);
507*4882a593Smuzhiyun     outb(0x00, nic_base + NE_EN0_RSARLO);
508*4882a593Smuzhiyun     outb(start_page, nic_base + NE_EN0_RSARHI);
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun     outb(E8390_RWRITE+E8390_START, nic_base + NE_CMD);
511*4882a593Smuzhiyun     if (ei_status.word16) {
512*4882a593Smuzhiyun         ptrs = (short*)buf;
513*4882a593Smuzhiyun         for (cnt = 0; cnt < count>>1; cnt++)
514*4882a593Smuzhiyun             outw(*ptrs++, NE_BASE+NE_DATAPORT);
515*4882a593Smuzhiyun     } else {
516*4882a593Smuzhiyun         ptrc = (char*)buf;
517*4882a593Smuzhiyun         for (cnt = 0; cnt < count; cnt++)
518*4882a593Smuzhiyun 	    outb(*ptrc++, NE_BASE + NE_DATAPORT);
519*4882a593Smuzhiyun     }
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun     dma_start = jiffies;
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun     while ((inb(NE_BASE + NE_EN0_ISR) & ENISR_RDC) == 0)
524*4882a593Smuzhiyun 	if (time_after(jiffies, dma_start + 2*HZ/100)) {	/* 20ms */
525*4882a593Smuzhiyun 		netdev_warn(dev, "timeout waiting for Tx RDC.\n");
526*4882a593Smuzhiyun 		apne_reset_8390(dev);
527*4882a593Smuzhiyun 		NS8390_init(dev,1);
528*4882a593Smuzhiyun 		break;
529*4882a593Smuzhiyun 	}
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun     outb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
532*4882a593Smuzhiyun     ei_status.dmaing &= ~0x01;
533*4882a593Smuzhiyun }
534*4882a593Smuzhiyun 
apne_interrupt(int irq,void * dev_id)535*4882a593Smuzhiyun static irqreturn_t apne_interrupt(int irq, void *dev_id)
536*4882a593Smuzhiyun {
537*4882a593Smuzhiyun     unsigned char pcmcia_intreq;
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun     if (!(gayle.inten & GAYLE_IRQ_IRQ))
540*4882a593Smuzhiyun         return IRQ_NONE;
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun     pcmcia_intreq = pcmcia_get_intreq();
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun     if (!(pcmcia_intreq & GAYLE_IRQ_IRQ)) {
545*4882a593Smuzhiyun         pcmcia_ack_int(pcmcia_intreq);
546*4882a593Smuzhiyun         return IRQ_NONE;
547*4882a593Smuzhiyun     }
548*4882a593Smuzhiyun     if (apne_msg_enable & NETIF_MSG_INTR)
549*4882a593Smuzhiyun 	pr_debug("pcmcia intreq = %x\n", pcmcia_intreq);
550*4882a593Smuzhiyun     pcmcia_disable_irq();			/* to get rid of the sti() within ei_interrupt */
551*4882a593Smuzhiyun     ei_interrupt(irq, dev_id);
552*4882a593Smuzhiyun     pcmcia_ack_int(pcmcia_get_intreq());
553*4882a593Smuzhiyun     pcmcia_enable_irq();
554*4882a593Smuzhiyun     return IRQ_HANDLED;
555*4882a593Smuzhiyun }
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun #ifdef MODULE
558*4882a593Smuzhiyun static struct net_device *apne_dev;
559*4882a593Smuzhiyun 
apne_module_init(void)560*4882a593Smuzhiyun static int __init apne_module_init(void)
561*4882a593Smuzhiyun {
562*4882a593Smuzhiyun 	apne_dev = apne_probe(-1);
563*4882a593Smuzhiyun 	return PTR_ERR_OR_ZERO(apne_dev);
564*4882a593Smuzhiyun }
565*4882a593Smuzhiyun 
apne_module_exit(void)566*4882a593Smuzhiyun static void __exit apne_module_exit(void)
567*4882a593Smuzhiyun {
568*4882a593Smuzhiyun 	unregister_netdev(apne_dev);
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	pcmcia_disable_irq();
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 	free_irq(IRQ_AMIGA_PORTS, apne_dev);
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 	pcmcia_reset();
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 	release_region(IOBASE, 0x20);
577*4882a593Smuzhiyun 
578*4882a593Smuzhiyun 	free_netdev(apne_dev);
579*4882a593Smuzhiyun }
580*4882a593Smuzhiyun module_init(apne_module_init);
581*4882a593Smuzhiyun module_exit(apne_module_exit);
582*4882a593Smuzhiyun #endif
583*4882a593Smuzhiyun 
init_pcmcia(void)584*4882a593Smuzhiyun static int init_pcmcia(void)
585*4882a593Smuzhiyun {
586*4882a593Smuzhiyun 	u_char config;
587*4882a593Smuzhiyun #ifndef MANUAL_CONFIG
588*4882a593Smuzhiyun 	u_char tuple[32];
589*4882a593Smuzhiyun 	int offset_len;
590*4882a593Smuzhiyun #endif
591*4882a593Smuzhiyun 	u_long offset;
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 	pcmcia_reset();
594*4882a593Smuzhiyun 	pcmcia_program_voltage(PCMCIA_0V);
595*4882a593Smuzhiyun 	pcmcia_access_speed(PCMCIA_SPEED_250NS);
596*4882a593Smuzhiyun 	pcmcia_write_enable();
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun #ifdef MANUAL_CONFIG
599*4882a593Smuzhiyun 	config = MANUAL_CONFIG;
600*4882a593Smuzhiyun #else
601*4882a593Smuzhiyun 	/* get and write config byte to enable IO port */
602*4882a593Smuzhiyun 
603*4882a593Smuzhiyun 	if (pcmcia_copy_tuple(CISTPL_CFTABLE_ENTRY, tuple, 32) < 3)
604*4882a593Smuzhiyun 		return 0;
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun 	config = tuple[2] & 0x3f;
607*4882a593Smuzhiyun #endif
608*4882a593Smuzhiyun #ifdef MANUAL_OFFSET
609*4882a593Smuzhiyun 	offset = MANUAL_OFFSET;
610*4882a593Smuzhiyun #else
611*4882a593Smuzhiyun 	if (pcmcia_copy_tuple(CISTPL_CONFIG, tuple, 32) < 6)
612*4882a593Smuzhiyun 		return 0;
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun 	offset_len = (tuple[2] & 0x3) + 1;
615*4882a593Smuzhiyun 	offset = 0;
616*4882a593Smuzhiyun 	while(offset_len--) {
617*4882a593Smuzhiyun 		offset = (offset << 8) | tuple[4+offset_len];
618*4882a593Smuzhiyun 	}
619*4882a593Smuzhiyun #endif
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun 	out_8(GAYLE_ATTRIBUTE+offset, config);
622*4882a593Smuzhiyun 
623*4882a593Smuzhiyun 	return 1;
624*4882a593Smuzhiyun }
625*4882a593Smuzhiyun 
626*4882a593Smuzhiyun MODULE_LICENSE("GPL");
627