xref: /titanic_51/usr/src/grub/grub-0.97/netboot/ns8390.c (revision 1b8adde7ba7d5e04395c141c5400dc2cffd7d809)
1*1b8adde7SWilliam Kucharski /**************************************************************************
2*1b8adde7SWilliam Kucharski ETHERBOOT -  BOOTP/TFTP Bootstrap Program
3*1b8adde7SWilliam Kucharski 
4*1b8adde7SWilliam Kucharski Author: Martin Renters
5*1b8adde7SWilliam Kucharski   Date: May/94
6*1b8adde7SWilliam Kucharski 
7*1b8adde7SWilliam Kucharski  This code is based heavily on David Greenman's if_ed.c driver
8*1b8adde7SWilliam Kucharski 
9*1b8adde7SWilliam Kucharski  Copyright (C) 1993-1994, David Greenman, Martin Renters.
10*1b8adde7SWilliam Kucharski   This software may be used, modified, copied, distributed, and sold, in
11*1b8adde7SWilliam Kucharski   both source and binary form provided that the above copyright and these
12*1b8adde7SWilliam Kucharski   terms are retained. Under no circumstances are the authors responsible for
13*1b8adde7SWilliam Kucharski   the proper functioning of this software, nor do the authors assume any
14*1b8adde7SWilliam Kucharski   responsibility for damages incurred with its use.
15*1b8adde7SWilliam Kucharski 
16*1b8adde7SWilliam Kucharski Multicast support added by Timothy Legge (timlegge@users.sourceforge.net) 09/28/2003
17*1b8adde7SWilliam Kucharski Relocation support added by Ken Yap (ken_yap@users.sourceforge.net) 28/12/02
18*1b8adde7SWilliam Kucharski 3c503 support added by Bill Paul (wpaul@ctr.columbia.edu) on 11/15/94
19*1b8adde7SWilliam Kucharski SMC8416 support added by Bill Paul (wpaul@ctr.columbia.edu) on 12/25/94
20*1b8adde7SWilliam Kucharski 3c503 PIO support added by Jim Hague (jim.hague@acm.org) on 2/17/98
21*1b8adde7SWilliam Kucharski RX overrun by Klaus Espenlaub (espenlaub@informatik.uni-ulm.de) on 3/10/99
22*1b8adde7SWilliam Kucharski   parts taken from the Linux 8390 driver (by Donald Becker and Paul Gortmaker)
23*1b8adde7SWilliam Kucharski SMC8416 PIO support added by Andrew Bettison (andrewb@zip.com.au) on 4/3/02
24*1b8adde7SWilliam Kucharski   based on the Linux 8390 driver (by Donald Becker and Paul Gortmaker)
25*1b8adde7SWilliam Kucharski 
26*1b8adde7SWilliam Kucharski **************************************************************************/
27*1b8adde7SWilliam Kucharski 
28*1b8adde7SWilliam Kucharski #include "etherboot.h"
29*1b8adde7SWilliam Kucharski #include "nic.h"
30*1b8adde7SWilliam Kucharski #include "ns8390.h"
31*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_NS8390
32*1b8adde7SWilliam Kucharski #include "pci.h"
33*1b8adde7SWilliam Kucharski #else
34*1b8adde7SWilliam Kucharski #include "isa.h"
35*1b8adde7SWilliam Kucharski #endif
36*1b8adde7SWilliam Kucharski 
37*1b8adde7SWilliam Kucharski static unsigned char	eth_vendor, eth_flags;
38*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_WD
39*1b8adde7SWilliam Kucharski static unsigned char	eth_laar;
40*1b8adde7SWilliam Kucharski #endif
41*1b8adde7SWilliam Kucharski static unsigned short	eth_nic_base, eth_asic_base;
42*1b8adde7SWilliam Kucharski static unsigned char	eth_memsize, eth_rx_start, eth_tx_start;
43*1b8adde7SWilliam Kucharski static Address		eth_bmem, eth_rmem;
44*1b8adde7SWilliam Kucharski static unsigned char	eth_drain_receiver;
45*1b8adde7SWilliam Kucharski 
46*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_WD
47*1b8adde7SWilliam Kucharski static struct wd_board {
48*1b8adde7SWilliam Kucharski 	const char *name;
49*1b8adde7SWilliam Kucharski 	char id;
50*1b8adde7SWilliam Kucharski 	char flags;
51*1b8adde7SWilliam Kucharski 	char memsize;
52*1b8adde7SWilliam Kucharski } wd_boards[] = {
53*1b8adde7SWilliam Kucharski 	{"WD8003S",	TYPE_WD8003S,	0,			MEM_8192},
54*1b8adde7SWilliam Kucharski 	{"WD8003E",	TYPE_WD8003E,	0,			MEM_8192},
55*1b8adde7SWilliam Kucharski 	{"WD8013EBT",	TYPE_WD8013EBT,	FLAG_16BIT,		MEM_16384},
56*1b8adde7SWilliam Kucharski 	{"WD8003W",	TYPE_WD8003W,	0,			MEM_8192},
57*1b8adde7SWilliam Kucharski 	{"WD8003EB",	TYPE_WD8003EB,	0,			MEM_8192},
58*1b8adde7SWilliam Kucharski 	{"WD8013W",	TYPE_WD8013W,	FLAG_16BIT,		MEM_16384},
59*1b8adde7SWilliam Kucharski 	{"WD8003EP/WD8013EP",
60*1b8adde7SWilliam Kucharski 			TYPE_WD8013EP,	0,			MEM_8192},
61*1b8adde7SWilliam Kucharski 	{"WD8013WC",	TYPE_WD8013WC,	FLAG_16BIT,		MEM_16384},
62*1b8adde7SWilliam Kucharski 	{"WD8013EPC",	TYPE_WD8013EPC,	FLAG_16BIT,		MEM_16384},
63*1b8adde7SWilliam Kucharski 	{"SMC8216T",	TYPE_SMC8216T,	FLAG_16BIT | FLAG_790,	MEM_16384},
64*1b8adde7SWilliam Kucharski 	{"SMC8216C",	TYPE_SMC8216C,	FLAG_16BIT | FLAG_790,	MEM_16384},
65*1b8adde7SWilliam Kucharski 	{"SMC8416T",	TYPE_SMC8416T,	FLAG_16BIT | FLAG_790,	MEM_8192},
66*1b8adde7SWilliam Kucharski 	{"SMC8416C/BT",	TYPE_SMC8416C,	FLAG_16BIT | FLAG_790,	MEM_8192},
67*1b8adde7SWilliam Kucharski 	{"SMC8013EBP",	TYPE_SMC8013EBP,FLAG_16BIT,		MEM_16384},
68*1b8adde7SWilliam Kucharski 	{NULL,		0,		0,			0}
69*1b8adde7SWilliam Kucharski };
70*1b8adde7SWilliam Kucharski #endif
71*1b8adde7SWilliam Kucharski 
72*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_3C503
73*1b8adde7SWilliam Kucharski static unsigned char	t503_output;	/* AUI or internal xcvr (Thinnet) */
74*1b8adde7SWilliam Kucharski #endif
75*1b8adde7SWilliam Kucharski 
76*1b8adde7SWilliam Kucharski #if	defined(INCLUDE_WD)
77*1b8adde7SWilliam Kucharski #define	ASIC_PIO	WD_IAR
78*1b8adde7SWilliam Kucharski #define	eth_probe	wd_probe
79*1b8adde7SWilliam Kucharski #if	defined(INCLUDE_3C503) || defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
80*1b8adde7SWilliam Kucharski Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
81*1b8adde7SWilliam Kucharski #endif
82*1b8adde7SWilliam Kucharski #endif
83*1b8adde7SWilliam Kucharski 
84*1b8adde7SWilliam Kucharski #if	defined(INCLUDE_3C503)
85*1b8adde7SWilliam Kucharski #define	eth_probe	t503_probe
86*1b8adde7SWilliam Kucharski #if	defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || defined(INCLUDE_WD)
87*1b8adde7SWilliam Kucharski Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
88*1b8adde7SWilliam Kucharski #endif
89*1b8adde7SWilliam Kucharski #endif
90*1b8adde7SWilliam Kucharski 
91*1b8adde7SWilliam Kucharski #if	defined(INCLUDE_NE)
92*1b8adde7SWilliam Kucharski #define	eth_probe	ne_probe
93*1b8adde7SWilliam Kucharski #if	defined(INCLUDE_NS8390) || defined(INCLUDE_3C503) || defined(INCLUDE_WD)
94*1b8adde7SWilliam Kucharski Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
95*1b8adde7SWilliam Kucharski #endif
96*1b8adde7SWilliam Kucharski #endif
97*1b8adde7SWilliam Kucharski 
98*1b8adde7SWilliam Kucharski #if	defined(INCLUDE_NS8390)
99*1b8adde7SWilliam Kucharski #define	eth_probe	nepci_probe
100*1b8adde7SWilliam Kucharski #if	defined(INCLUDE_NE) || defined(INCLUDE_3C503) || defined(INCLUDE_WD)
101*1b8adde7SWilliam Kucharski Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
102*1b8adde7SWilliam Kucharski #endif
103*1b8adde7SWilliam Kucharski #endif
104*1b8adde7SWilliam Kucharski 
105*1b8adde7SWilliam Kucharski #if	defined(INCLUDE_3C503)
106*1b8adde7SWilliam Kucharski #define	ASIC_PIO	_3COM_RFMSB
107*1b8adde7SWilliam Kucharski #else
108*1b8adde7SWilliam Kucharski #if	defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
109*1b8adde7SWilliam Kucharski #define	ASIC_PIO	NE_DATA
110*1b8adde7SWilliam Kucharski #endif
111*1b8adde7SWilliam Kucharski #endif
112*1b8adde7SWilliam Kucharski 
113*1b8adde7SWilliam Kucharski #if	defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || (defined(INCLUDE_3C503) && !defined(T503_SHMEM)) || (defined(INCLUDE_WD) && defined(WD_790_PIO))
114*1b8adde7SWilliam Kucharski /**************************************************************************
115*1b8adde7SWilliam Kucharski ETH_PIO_READ - Read a frame via Programmed I/O
116*1b8adde7SWilliam Kucharski **************************************************************************/
117*1b8adde7SWilliam Kucharski static void eth_pio_read(unsigned int src, unsigned char *dst, unsigned int cnt)
118*1b8adde7SWilliam Kucharski {
119*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_WD
120*1b8adde7SWilliam Kucharski 	outb(src & 0xff, eth_asic_base + WD_GP2);
121*1b8adde7SWilliam Kucharski 	outb(src >> 8, eth_asic_base + WD_GP2);
122*1b8adde7SWilliam Kucharski #else
123*1b8adde7SWilliam Kucharski 	outb(D8390_COMMAND_RD2 |
124*1b8adde7SWilliam Kucharski 		D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
125*1b8adde7SWilliam Kucharski 	outb(cnt, eth_nic_base + D8390_P0_RBCR0);
126*1b8adde7SWilliam Kucharski 	outb(cnt>>8, eth_nic_base + D8390_P0_RBCR1);
127*1b8adde7SWilliam Kucharski 	outb(src, eth_nic_base + D8390_P0_RSAR0);
128*1b8adde7SWilliam Kucharski 	outb(src>>8, eth_nic_base + D8390_P0_RSAR1);
129*1b8adde7SWilliam Kucharski 	outb(D8390_COMMAND_RD0 |
130*1b8adde7SWilliam Kucharski 		D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
131*1b8adde7SWilliam Kucharski 
132*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_3C503
133*1b8adde7SWilliam Kucharski 	outb(src & 0xff, eth_asic_base + _3COM_DALSB);
134*1b8adde7SWilliam Kucharski 	outb(src >> 8, eth_asic_base + _3COM_DAMSB);
135*1b8adde7SWilliam Kucharski 	outb(t503_output | _3COM_CR_START, eth_asic_base + _3COM_CR);
136*1b8adde7SWilliam Kucharski #endif
137*1b8adde7SWilliam Kucharski #endif
138*1b8adde7SWilliam Kucharski 
139*1b8adde7SWilliam Kucharski 	if (eth_flags & FLAG_16BIT)
140*1b8adde7SWilliam Kucharski 		cnt = (cnt + 1) >> 1;
141*1b8adde7SWilliam Kucharski 
142*1b8adde7SWilliam Kucharski 	while(cnt--) {
143*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_3C503
144*1b8adde7SWilliam Kucharski 		while((inb(eth_asic_base + _3COM_STREG) & _3COM_STREG_DPRDY) == 0)
145*1b8adde7SWilliam Kucharski 			;
146*1b8adde7SWilliam Kucharski #endif
147*1b8adde7SWilliam Kucharski 
148*1b8adde7SWilliam Kucharski 		if (eth_flags & FLAG_16BIT) {
149*1b8adde7SWilliam Kucharski 			*((unsigned short *)dst) = inw(eth_asic_base + ASIC_PIO);
150*1b8adde7SWilliam Kucharski 			dst += 2;
151*1b8adde7SWilliam Kucharski 		}
152*1b8adde7SWilliam Kucharski 		else
153*1b8adde7SWilliam Kucharski 			*(dst++) = inb(eth_asic_base + ASIC_PIO);
154*1b8adde7SWilliam Kucharski 	}
155*1b8adde7SWilliam Kucharski 
156*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_3C503
157*1b8adde7SWilliam Kucharski 	outb(t503_output, eth_asic_base + _3COM_CR);
158*1b8adde7SWilliam Kucharski #endif
159*1b8adde7SWilliam Kucharski }
160*1b8adde7SWilliam Kucharski 
161*1b8adde7SWilliam Kucharski /**************************************************************************
162*1b8adde7SWilliam Kucharski ETH_PIO_WRITE - Write a frame via Programmed I/O
163*1b8adde7SWilliam Kucharski **************************************************************************/
164*1b8adde7SWilliam Kucharski static void eth_pio_write(const unsigned char *src, unsigned int dst, unsigned int cnt)
165*1b8adde7SWilliam Kucharski {
166*1b8adde7SWilliam Kucharski #ifdef	COMPEX_RL2000_FIX
167*1b8adde7SWilliam Kucharski 	unsigned int x;
168*1b8adde7SWilliam Kucharski #endif	/* COMPEX_RL2000_FIX */
169*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_WD
170*1b8adde7SWilliam Kucharski 	outb(dst & 0xff, eth_asic_base + WD_GP2);
171*1b8adde7SWilliam Kucharski 	outb(dst >> 8, eth_asic_base + WD_GP2);
172*1b8adde7SWilliam Kucharski #else
173*1b8adde7SWilliam Kucharski 	outb(D8390_COMMAND_RD2 |
174*1b8adde7SWilliam Kucharski 		D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
175*1b8adde7SWilliam Kucharski 	outb(D8390_ISR_RDC, eth_nic_base + D8390_P0_ISR);
176*1b8adde7SWilliam Kucharski 	outb(cnt, eth_nic_base + D8390_P0_RBCR0);
177*1b8adde7SWilliam Kucharski 	outb(cnt>>8, eth_nic_base + D8390_P0_RBCR1);
178*1b8adde7SWilliam Kucharski 	outb(dst, eth_nic_base + D8390_P0_RSAR0);
179*1b8adde7SWilliam Kucharski 	outb(dst>>8, eth_nic_base + D8390_P0_RSAR1);
180*1b8adde7SWilliam Kucharski 	outb(D8390_COMMAND_RD1 |
181*1b8adde7SWilliam Kucharski 		D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
182*1b8adde7SWilliam Kucharski 
183*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_3C503
184*1b8adde7SWilliam Kucharski 	outb(dst & 0xff, eth_asic_base + _3COM_DALSB);
185*1b8adde7SWilliam Kucharski 	outb(dst >> 8, eth_asic_base + _3COM_DAMSB);
186*1b8adde7SWilliam Kucharski 
187*1b8adde7SWilliam Kucharski 	outb(t503_output | _3COM_CR_DDIR | _3COM_CR_START, eth_asic_base + _3COM_CR);
188*1b8adde7SWilliam Kucharski #endif
189*1b8adde7SWilliam Kucharski #endif
190*1b8adde7SWilliam Kucharski 
191*1b8adde7SWilliam Kucharski 	if (eth_flags & FLAG_16BIT)
192*1b8adde7SWilliam Kucharski 		cnt = (cnt + 1) >> 1;
193*1b8adde7SWilliam Kucharski 
194*1b8adde7SWilliam Kucharski 	while(cnt--)
195*1b8adde7SWilliam Kucharski 	{
196*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_3C503
197*1b8adde7SWilliam Kucharski 		while((inb(eth_asic_base + _3COM_STREG) & _3COM_STREG_DPRDY) == 0)
198*1b8adde7SWilliam Kucharski 			;
199*1b8adde7SWilliam Kucharski #endif
200*1b8adde7SWilliam Kucharski 
201*1b8adde7SWilliam Kucharski 		if (eth_flags & FLAG_16BIT) {
202*1b8adde7SWilliam Kucharski 			outw(*((unsigned short *)src), eth_asic_base + ASIC_PIO);
203*1b8adde7SWilliam Kucharski 			src += 2;
204*1b8adde7SWilliam Kucharski 		}
205*1b8adde7SWilliam Kucharski 		else
206*1b8adde7SWilliam Kucharski 			outb(*(src++), eth_asic_base + ASIC_PIO);
207*1b8adde7SWilliam Kucharski 	}
208*1b8adde7SWilliam Kucharski 
209*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_3C503
210*1b8adde7SWilliam Kucharski 	outb(t503_output, eth_asic_base + _3COM_CR);
211*1b8adde7SWilliam Kucharski #else
212*1b8adde7SWilliam Kucharski #ifdef	COMPEX_RL2000_FIX
213*1b8adde7SWilliam Kucharski 	for (x = 0;
214*1b8adde7SWilliam Kucharski 		x < COMPEX_RL2000_TRIES &&
215*1b8adde7SWilliam Kucharski 		(inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC)
216*1b8adde7SWilliam Kucharski 		!= D8390_ISR_RDC;
217*1b8adde7SWilliam Kucharski 		++x);
218*1b8adde7SWilliam Kucharski 	if (x >= COMPEX_RL2000_TRIES)
219*1b8adde7SWilliam Kucharski 		printf("Warning: Compex RL2000 aborted wait!\n");
220*1b8adde7SWilliam Kucharski #endif	/* COMPEX_RL2000_FIX */
221*1b8adde7SWilliam Kucharski #ifndef	INCLUDE_WD
222*1b8adde7SWilliam Kucharski 	while((inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC)
223*1b8adde7SWilliam Kucharski 		!= D8390_ISR_RDC);
224*1b8adde7SWilliam Kucharski #endif
225*1b8adde7SWilliam Kucharski #endif
226*1b8adde7SWilliam Kucharski }
227*1b8adde7SWilliam Kucharski #else
228*1b8adde7SWilliam Kucharski /**************************************************************************
229*1b8adde7SWilliam Kucharski ETH_PIO_READ - Dummy routine when NE2000 not compiled in
230*1b8adde7SWilliam Kucharski **************************************************************************/
231*1b8adde7SWilliam Kucharski static void eth_pio_read(unsigned int src __unused, unsigned char *dst  __unused, unsigned int cnt __unused) {}
232*1b8adde7SWilliam Kucharski #endif
233*1b8adde7SWilliam Kucharski 
234*1b8adde7SWilliam Kucharski 
235*1b8adde7SWilliam Kucharski /**************************************************************************
236*1b8adde7SWilliam Kucharski enable_multycast - Enable Multicast
237*1b8adde7SWilliam Kucharski **************************************************************************/
238*1b8adde7SWilliam Kucharski static void enable_multicast(unsigned short eth_nic_base)
239*1b8adde7SWilliam Kucharski {
240*1b8adde7SWilliam Kucharski 	unsigned char mcfilter[8];
241*1b8adde7SWilliam Kucharski 	int i;
242*1b8adde7SWilliam Kucharski 	memset(mcfilter, 0xFF, 8);
243*1b8adde7SWilliam Kucharski 	outb(4, eth_nic_base+D8390_P0_RCR);
244*1b8adde7SWilliam Kucharski 	outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS1, eth_nic_base + D8390_P0_COMMAND);
245*1b8adde7SWilliam Kucharski 	for(i=0;i<8;i++)
246*1b8adde7SWilliam Kucharski 	{
247*1b8adde7SWilliam Kucharski 		outb(mcfilter[i], eth_nic_base + 8 + i);
248*1b8adde7SWilliam Kucharski 		if(inb(eth_nic_base + 8 + i)!=mcfilter[i])
249*1b8adde7SWilliam Kucharski 			printf("Error SMC 83C690 Multicast filter read/write mishap %d\n",i);
250*1b8adde7SWilliam Kucharski 	}
251*1b8adde7SWilliam Kucharski 	outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS0, eth_nic_base + D8390_P0_COMMAND);
252*1b8adde7SWilliam Kucharski 	outb(4 | 0x08, eth_nic_base+D8390_P0_RCR);
253*1b8adde7SWilliam Kucharski }
254*1b8adde7SWilliam Kucharski 
255*1b8adde7SWilliam Kucharski /**************************************************************************
256*1b8adde7SWilliam Kucharski NS8390_RESET - Reset adapter
257*1b8adde7SWilliam Kucharski **************************************************************************/
258*1b8adde7SWilliam Kucharski static void ns8390_reset(struct nic *nic)
259*1b8adde7SWilliam Kucharski {
260*1b8adde7SWilliam Kucharski 	int i;
261*1b8adde7SWilliam Kucharski 
262*1b8adde7SWilliam Kucharski 	eth_drain_receiver = 0;
263*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_WD
264*1b8adde7SWilliam Kucharski 	if (eth_flags & FLAG_790)
265*1b8adde7SWilliam Kucharski 		outb(D8390_COMMAND_PS0 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
266*1b8adde7SWilliam Kucharski 	else
267*1b8adde7SWilliam Kucharski #endif
268*1b8adde7SWilliam Kucharski 		outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
269*1b8adde7SWilliam Kucharski 			D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
270*1b8adde7SWilliam Kucharski 	if (eth_flags & FLAG_16BIT)
271*1b8adde7SWilliam Kucharski 		outb(0x49, eth_nic_base+D8390_P0_DCR);
272*1b8adde7SWilliam Kucharski 	else
273*1b8adde7SWilliam Kucharski 		outb(0x48, eth_nic_base+D8390_P0_DCR);
274*1b8adde7SWilliam Kucharski 	outb(0, eth_nic_base+D8390_P0_RBCR0);
275*1b8adde7SWilliam Kucharski 	outb(0, eth_nic_base+D8390_P0_RBCR1);
276*1b8adde7SWilliam Kucharski 	outb(0x20, eth_nic_base+D8390_P0_RCR);	/* monitor mode */
277*1b8adde7SWilliam Kucharski 	outb(2, eth_nic_base+D8390_P0_TCR);
278*1b8adde7SWilliam Kucharski 	outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR);
279*1b8adde7SWilliam Kucharski 	outb(eth_rx_start, eth_nic_base+D8390_P0_PSTART);
280*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_WD
281*1b8adde7SWilliam Kucharski 	if (eth_flags & FLAG_790) {
282*1b8adde7SWilliam Kucharski #ifdef	WD_790_PIO
283*1b8adde7SWilliam Kucharski 		outb(0x10, eth_asic_base + 0x06); /* disable interrupts, enable PIO */
284*1b8adde7SWilliam Kucharski 		outb(0x01, eth_nic_base + 0x09); /* enable ring read auto-wrap */
285*1b8adde7SWilliam Kucharski #else
286*1b8adde7SWilliam Kucharski 		outb(0, eth_nic_base + 0x09);
287*1b8adde7SWilliam Kucharski #endif
288*1b8adde7SWilliam Kucharski 	}
289*1b8adde7SWilliam Kucharski #endif
290*1b8adde7SWilliam Kucharski 	outb(eth_memsize, eth_nic_base+D8390_P0_PSTOP);
291*1b8adde7SWilliam Kucharski 	outb(eth_memsize - 1, eth_nic_base+D8390_P0_BOUND);
292*1b8adde7SWilliam Kucharski 	outb(0xFF, eth_nic_base+D8390_P0_ISR);
293*1b8adde7SWilliam Kucharski 	outb(0, eth_nic_base+D8390_P0_IMR);
294*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_WD
295*1b8adde7SWilliam Kucharski 	if (eth_flags & FLAG_790)
296*1b8adde7SWilliam Kucharski 		outb(D8390_COMMAND_PS1 |
297*1b8adde7SWilliam Kucharski 			D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
298*1b8adde7SWilliam Kucharski 	else
299*1b8adde7SWilliam Kucharski #endif
300*1b8adde7SWilliam Kucharski 		outb(D8390_COMMAND_PS1 |
301*1b8adde7SWilliam Kucharski 			D8390_COMMAND_RD2 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
302*1b8adde7SWilliam Kucharski 	for (i=0; i<ETH_ALEN; i++)
303*1b8adde7SWilliam Kucharski 		outb(nic->node_addr[i], eth_nic_base+D8390_P1_PAR0+i);
304*1b8adde7SWilliam Kucharski 	for (i=0; i<ETH_ALEN; i++)
305*1b8adde7SWilliam Kucharski 		outb(0xFF, eth_nic_base+D8390_P1_MAR0+i);
306*1b8adde7SWilliam Kucharski 	outb(eth_rx_start, eth_nic_base+D8390_P1_CURR);
307*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_WD
308*1b8adde7SWilliam Kucharski 	if (eth_flags & FLAG_790)
309*1b8adde7SWilliam Kucharski 		outb(D8390_COMMAND_PS0 |
310*1b8adde7SWilliam Kucharski 			D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
311*1b8adde7SWilliam Kucharski 	else
312*1b8adde7SWilliam Kucharski #endif
313*1b8adde7SWilliam Kucharski 		outb(D8390_COMMAND_PS0 |
314*1b8adde7SWilliam Kucharski 			D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
315*1b8adde7SWilliam Kucharski 	outb(0xFF, eth_nic_base+D8390_P0_ISR);
316*1b8adde7SWilliam Kucharski 	outb(0, eth_nic_base+D8390_P0_TCR);	/* transmitter on */
317*1b8adde7SWilliam Kucharski 	outb(4, eth_nic_base+D8390_P0_RCR);	/* allow rx broadcast frames */
318*1b8adde7SWilliam Kucharski 
319*1b8adde7SWilliam Kucharski 	enable_multicast(eth_nic_base);
320*1b8adde7SWilliam Kucharski 
321*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_3C503
322*1b8adde7SWilliam Kucharski         /*
323*1b8adde7SWilliam Kucharski          * No way to tell whether or not we're supposed to use
324*1b8adde7SWilliam Kucharski          * the 3Com's transceiver unless the user tells us.
325*1b8adde7SWilliam Kucharski          * 'flags' should have some compile time default value
326*1b8adde7SWilliam Kucharski          * which can be changed from the command menu.
327*1b8adde7SWilliam Kucharski          */
328*1b8adde7SWilliam Kucharski 	t503_output = (nic->flags) ? 0 : _3COM_CR_XSEL;
329*1b8adde7SWilliam Kucharski 	outb(t503_output, eth_asic_base + _3COM_CR);
330*1b8adde7SWilliam Kucharski #endif
331*1b8adde7SWilliam Kucharski }
332*1b8adde7SWilliam Kucharski 
333*1b8adde7SWilliam Kucharski static int ns8390_poll(struct nic *nic, int retrieve);
334*1b8adde7SWilliam Kucharski 
335*1b8adde7SWilliam Kucharski #ifndef	INCLUDE_3C503
336*1b8adde7SWilliam Kucharski /**************************************************************************
337*1b8adde7SWilliam Kucharski ETH_RX_OVERRUN - Bring adapter back to work after an RX overrun
338*1b8adde7SWilliam Kucharski **************************************************************************/
339*1b8adde7SWilliam Kucharski static void eth_rx_overrun(struct nic *nic)
340*1b8adde7SWilliam Kucharski {
341*1b8adde7SWilliam Kucharski 	int start_time;
342*1b8adde7SWilliam Kucharski 
343*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_WD
344*1b8adde7SWilliam Kucharski 	if (eth_flags & FLAG_790)
345*1b8adde7SWilliam Kucharski 		outb(D8390_COMMAND_PS0 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
346*1b8adde7SWilliam Kucharski 	else
347*1b8adde7SWilliam Kucharski #endif
348*1b8adde7SWilliam Kucharski 		outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
349*1b8adde7SWilliam Kucharski 			D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
350*1b8adde7SWilliam Kucharski 
351*1b8adde7SWilliam Kucharski 	/* wait for at least 1.6ms - we wait one timer tick */
352*1b8adde7SWilliam Kucharski 	start_time = currticks();
353*1b8adde7SWilliam Kucharski 	while (currticks() - start_time <= 1)
354*1b8adde7SWilliam Kucharski 		/* Nothing */;
355*1b8adde7SWilliam Kucharski 
356*1b8adde7SWilliam Kucharski 	outb(0, eth_nic_base+D8390_P0_RBCR0);	/* reset byte counter */
357*1b8adde7SWilliam Kucharski 	outb(0, eth_nic_base+D8390_P0_RBCR1);
358*1b8adde7SWilliam Kucharski 
359*1b8adde7SWilliam Kucharski 	/*
360*1b8adde7SWilliam Kucharski 	 * Linux driver checks for interrupted TX here. This is not necessary,
361*1b8adde7SWilliam Kucharski 	 * because the transmit routine waits until the frame is sent.
362*1b8adde7SWilliam Kucharski 	 */
363*1b8adde7SWilliam Kucharski 
364*1b8adde7SWilliam Kucharski 	/* enter loopback mode and restart NIC */
365*1b8adde7SWilliam Kucharski 	outb(2, eth_nic_base+D8390_P0_TCR);
366*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_WD
367*1b8adde7SWilliam Kucharski 	if (eth_flags & FLAG_790)
368*1b8adde7SWilliam Kucharski 		outb(D8390_COMMAND_PS0 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
369*1b8adde7SWilliam Kucharski 	else
370*1b8adde7SWilliam Kucharski #endif
371*1b8adde7SWilliam Kucharski 		outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
372*1b8adde7SWilliam Kucharski 			D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
373*1b8adde7SWilliam Kucharski 
374*1b8adde7SWilliam Kucharski 	/* clear the RX ring, acknowledge overrun interrupt */
375*1b8adde7SWilliam Kucharski 	eth_drain_receiver = 1;
376*1b8adde7SWilliam Kucharski 	while (ns8390_poll(nic, 1))
377*1b8adde7SWilliam Kucharski 		/* Nothing */;
378*1b8adde7SWilliam Kucharski 	eth_drain_receiver = 0;
379*1b8adde7SWilliam Kucharski 	outb(D8390_ISR_OVW, eth_nic_base+D8390_P0_ISR);
380*1b8adde7SWilliam Kucharski 
381*1b8adde7SWilliam Kucharski 	/* leave loopback mode - no packets to be resent (see Linux driver) */
382*1b8adde7SWilliam Kucharski 	outb(0, eth_nic_base+D8390_P0_TCR);
383*1b8adde7SWilliam Kucharski }
384*1b8adde7SWilliam Kucharski #endif	/* INCLUDE_3C503 */
385*1b8adde7SWilliam Kucharski 
386*1b8adde7SWilliam Kucharski /**************************************************************************
387*1b8adde7SWilliam Kucharski NS8390_TRANSMIT - Transmit a frame
388*1b8adde7SWilliam Kucharski **************************************************************************/
389*1b8adde7SWilliam Kucharski static void ns8390_transmit(
390*1b8adde7SWilliam Kucharski 	struct nic *nic,
391*1b8adde7SWilliam Kucharski 	const char *d,			/* Destination */
392*1b8adde7SWilliam Kucharski 	unsigned int t,			/* Type */
393*1b8adde7SWilliam Kucharski 	unsigned int s,			/* size */
394*1b8adde7SWilliam Kucharski 	const char *p)			/* Packet */
395*1b8adde7SWilliam Kucharski {
396*1b8adde7SWilliam Kucharski #if defined(INCLUDE_3C503) || (defined(INCLUDE_WD) && ! defined(WD_790_PIO))
397*1b8adde7SWilliam Kucharski 	Address		eth_vmem = bus_to_virt(eth_bmem);
398*1b8adde7SWilliam Kucharski #endif
399*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_3C503
400*1b8adde7SWilliam Kucharski         if (!(eth_flags & FLAG_PIO)) {
401*1b8adde7SWilliam Kucharski                 memcpy((char *)eth_vmem, d, ETH_ALEN);	/* dst */
402*1b8adde7SWilliam Kucharski                 memcpy((char *)eth_vmem+ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */
403*1b8adde7SWilliam Kucharski                 *((char *)eth_vmem+12) = t>>8;		/* type */
404*1b8adde7SWilliam Kucharski                 *((char *)eth_vmem+13) = t;
405*1b8adde7SWilliam Kucharski                 memcpy((char *)eth_vmem+ETH_HLEN, p, s);
406*1b8adde7SWilliam Kucharski                 s += ETH_HLEN;
407*1b8adde7SWilliam Kucharski                 while (s < ETH_ZLEN) *((char *)eth_vmem+(s++)) = 0;
408*1b8adde7SWilliam Kucharski         }
409*1b8adde7SWilliam Kucharski #endif
410*1b8adde7SWilliam Kucharski 
411*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_WD
412*1b8adde7SWilliam Kucharski 	if (eth_flags & FLAG_16BIT) {
413*1b8adde7SWilliam Kucharski 		outb(eth_laar | WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
414*1b8adde7SWilliam Kucharski 		inb(0x84);
415*1b8adde7SWilliam Kucharski 	}
416*1b8adde7SWilliam Kucharski #ifndef	WD_790_PIO
417*1b8adde7SWilliam Kucharski 	/* Memory interface */
418*1b8adde7SWilliam Kucharski 	if (eth_flags & FLAG_790) {
419*1b8adde7SWilliam Kucharski 		outb(WD_MSR_MENB, eth_asic_base + WD_MSR);
420*1b8adde7SWilliam Kucharski 		inb(0x84);
421*1b8adde7SWilliam Kucharski 	}
422*1b8adde7SWilliam Kucharski 	inb(0x84);
423*1b8adde7SWilliam Kucharski 	memcpy((char *)eth_vmem, d, ETH_ALEN);	/* dst */
424*1b8adde7SWilliam Kucharski 	memcpy((char *)eth_vmem+ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */
425*1b8adde7SWilliam Kucharski 	*((char *)eth_vmem+12) = t>>8;		/* type */
426*1b8adde7SWilliam Kucharski 	*((char *)eth_vmem+13) = t;
427*1b8adde7SWilliam Kucharski 	memcpy((char *)eth_vmem+ETH_HLEN, p, s);
428*1b8adde7SWilliam Kucharski 	s += ETH_HLEN;
429*1b8adde7SWilliam Kucharski 	while (s < ETH_ZLEN) *((char *)eth_vmem+(s++)) = 0;
430*1b8adde7SWilliam Kucharski 	if (eth_flags & FLAG_790) {
431*1b8adde7SWilliam Kucharski 		outb(0, eth_asic_base + WD_MSR);
432*1b8adde7SWilliam Kucharski 		inb(0x84);
433*1b8adde7SWilliam Kucharski 	}
434*1b8adde7SWilliam Kucharski #else
435*1b8adde7SWilliam Kucharski 	inb(0x84);
436*1b8adde7SWilliam Kucharski #endif
437*1b8adde7SWilliam Kucharski #endif
438*1b8adde7SWilliam Kucharski 
439*1b8adde7SWilliam Kucharski #if	defined(INCLUDE_3C503)
440*1b8adde7SWilliam Kucharski 	if (eth_flags & FLAG_PIO)
441*1b8adde7SWilliam Kucharski #endif
442*1b8adde7SWilliam Kucharski #if	defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || (defined(INCLUDE_3C503) && !defined(T503_SHMEM)) || (defined(INCLUDE_WD) && defined(WD_790_PIO))
443*1b8adde7SWilliam Kucharski 	{
444*1b8adde7SWilliam Kucharski 		/* Programmed I/O */
445*1b8adde7SWilliam Kucharski 		unsigned short type;
446*1b8adde7SWilliam Kucharski 		type = (t >> 8) | (t << 8);
447*1b8adde7SWilliam Kucharski 		eth_pio_write(d, eth_tx_start<<8, ETH_ALEN);
448*1b8adde7SWilliam Kucharski 		eth_pio_write(nic->node_addr, (eth_tx_start<<8)+ETH_ALEN, ETH_ALEN);
449*1b8adde7SWilliam Kucharski 		/* bcc generates worse code without (const+const) below */
450*1b8adde7SWilliam Kucharski 		eth_pio_write((unsigned char *)&type, (eth_tx_start<<8)+(ETH_ALEN+ETH_ALEN), 2);
451*1b8adde7SWilliam Kucharski 		eth_pio_write(p, (eth_tx_start<<8)+ETH_HLEN, s);
452*1b8adde7SWilliam Kucharski 		s += ETH_HLEN;
453*1b8adde7SWilliam Kucharski 		if (s < ETH_ZLEN) s = ETH_ZLEN;
454*1b8adde7SWilliam Kucharski 	}
455*1b8adde7SWilliam Kucharski #endif
456*1b8adde7SWilliam Kucharski #if	defined(INCLUDE_3C503)
457*1b8adde7SWilliam Kucharski #endif
458*1b8adde7SWilliam Kucharski 
459*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_WD
460*1b8adde7SWilliam Kucharski 	if (eth_flags & FLAG_16BIT) {
461*1b8adde7SWilliam Kucharski 		outb(eth_laar & ~WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
462*1b8adde7SWilliam Kucharski 		inb(0x84);
463*1b8adde7SWilliam Kucharski 	}
464*1b8adde7SWilliam Kucharski 	if (eth_flags & FLAG_790)
465*1b8adde7SWilliam Kucharski 		outb(D8390_COMMAND_PS0 |
466*1b8adde7SWilliam Kucharski 			D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
467*1b8adde7SWilliam Kucharski 	else
468*1b8adde7SWilliam Kucharski #endif
469*1b8adde7SWilliam Kucharski 		outb(D8390_COMMAND_PS0 |
470*1b8adde7SWilliam Kucharski 			D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
471*1b8adde7SWilliam Kucharski 	outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR);
472*1b8adde7SWilliam Kucharski 	outb(s, eth_nic_base+D8390_P0_TBCR0);
473*1b8adde7SWilliam Kucharski 	outb(s>>8, eth_nic_base+D8390_P0_TBCR1);
474*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_WD
475*1b8adde7SWilliam Kucharski 	if (eth_flags & FLAG_790)
476*1b8adde7SWilliam Kucharski 		outb(D8390_COMMAND_PS0 |
477*1b8adde7SWilliam Kucharski 			D8390_COMMAND_TXP | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
478*1b8adde7SWilliam Kucharski 	else
479*1b8adde7SWilliam Kucharski #endif
480*1b8adde7SWilliam Kucharski 		outb(D8390_COMMAND_PS0 |
481*1b8adde7SWilliam Kucharski 			D8390_COMMAND_TXP | D8390_COMMAND_RD2 |
482*1b8adde7SWilliam Kucharski 			D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
483*1b8adde7SWilliam Kucharski }
484*1b8adde7SWilliam Kucharski 
485*1b8adde7SWilliam Kucharski /**************************************************************************
486*1b8adde7SWilliam Kucharski NS8390_POLL - Wait for a frame
487*1b8adde7SWilliam Kucharski **************************************************************************/
488*1b8adde7SWilliam Kucharski static int ns8390_poll(struct nic *nic, int retrieve)
489*1b8adde7SWilliam Kucharski {
490*1b8adde7SWilliam Kucharski 	int ret = 0;
491*1b8adde7SWilliam Kucharski 	unsigned char rstat, curr, next;
492*1b8adde7SWilliam Kucharski 	unsigned short len, frag;
493*1b8adde7SWilliam Kucharski 	unsigned short pktoff;
494*1b8adde7SWilliam Kucharski 	unsigned char *p;
495*1b8adde7SWilliam Kucharski 	struct ringbuffer pkthdr;
496*1b8adde7SWilliam Kucharski 
497*1b8adde7SWilliam Kucharski #ifndef	INCLUDE_3C503
498*1b8adde7SWilliam Kucharski 	/* avoid infinite recursion: see eth_rx_overrun() */
499*1b8adde7SWilliam Kucharski 	if (!eth_drain_receiver && (inb(eth_nic_base+D8390_P0_ISR) & D8390_ISR_OVW)) {
500*1b8adde7SWilliam Kucharski 		eth_rx_overrun(nic);
501*1b8adde7SWilliam Kucharski 		return(0);
502*1b8adde7SWilliam Kucharski 	}
503*1b8adde7SWilliam Kucharski #endif	/* INCLUDE_3C503 */
504*1b8adde7SWilliam Kucharski 	rstat = inb(eth_nic_base+D8390_P0_RSR);
505*1b8adde7SWilliam Kucharski 	if (!(rstat & D8390_RSTAT_PRX)) return(0);
506*1b8adde7SWilliam Kucharski 	next = inb(eth_nic_base+D8390_P0_BOUND)+1;
507*1b8adde7SWilliam Kucharski 	if (next >= eth_memsize) next = eth_rx_start;
508*1b8adde7SWilliam Kucharski 	outb(D8390_COMMAND_PS1, eth_nic_base+D8390_P0_COMMAND);
509*1b8adde7SWilliam Kucharski 	curr = inb(eth_nic_base+D8390_P1_CURR);
510*1b8adde7SWilliam Kucharski 	outb(D8390_COMMAND_PS0, eth_nic_base+D8390_P0_COMMAND);
511*1b8adde7SWilliam Kucharski 	if (curr >= eth_memsize) curr=eth_rx_start;
512*1b8adde7SWilliam Kucharski 	if (curr == next) return(0);
513*1b8adde7SWilliam Kucharski 
514*1b8adde7SWilliam Kucharski 	if ( ! retrieve ) return 1;
515*1b8adde7SWilliam Kucharski 
516*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_WD
517*1b8adde7SWilliam Kucharski 	if (eth_flags & FLAG_16BIT) {
518*1b8adde7SWilliam Kucharski 		outb(eth_laar | WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
519*1b8adde7SWilliam Kucharski 		inb(0x84);
520*1b8adde7SWilliam Kucharski 	}
521*1b8adde7SWilliam Kucharski #ifndef	WD_790_PIO
522*1b8adde7SWilliam Kucharski 	if (eth_flags & FLAG_790) {
523*1b8adde7SWilliam Kucharski 		outb(WD_MSR_MENB, eth_asic_base + WD_MSR);
524*1b8adde7SWilliam Kucharski 		inb(0x84);
525*1b8adde7SWilliam Kucharski 	}
526*1b8adde7SWilliam Kucharski #endif
527*1b8adde7SWilliam Kucharski 	inb(0x84);
528*1b8adde7SWilliam Kucharski #endif
529*1b8adde7SWilliam Kucharski 	pktoff = next << 8;
530*1b8adde7SWilliam Kucharski 	if (eth_flags & FLAG_PIO)
531*1b8adde7SWilliam Kucharski 		eth_pio_read(pktoff, (char *)&pkthdr, 4);
532*1b8adde7SWilliam Kucharski 	else
533*1b8adde7SWilliam Kucharski 		memcpy(&pkthdr, bus_to_virt(eth_rmem + pktoff), 4);
534*1b8adde7SWilliam Kucharski 	pktoff += sizeof(pkthdr);
535*1b8adde7SWilliam Kucharski 	/* incoming length includes FCS so must sub 4 */
536*1b8adde7SWilliam Kucharski 	len = pkthdr.len - 4;
537*1b8adde7SWilliam Kucharski 	if ((pkthdr.status & D8390_RSTAT_PRX) == 0 || len < ETH_ZLEN
538*1b8adde7SWilliam Kucharski 		|| len > ETH_FRAME_LEN) {
539*1b8adde7SWilliam Kucharski 		printf("Bogus packet, ignoring\n");
540*1b8adde7SWilliam Kucharski 		return (0);
541*1b8adde7SWilliam Kucharski 	}
542*1b8adde7SWilliam Kucharski 	else {
543*1b8adde7SWilliam Kucharski 		p = nic->packet;
544*1b8adde7SWilliam Kucharski 		nic->packetlen = len;		/* available to caller */
545*1b8adde7SWilliam Kucharski 		frag = (eth_memsize << 8) - pktoff;
546*1b8adde7SWilliam Kucharski 		if (len > frag) {		/* We have a wrap-around */
547*1b8adde7SWilliam Kucharski 			/* read first part */
548*1b8adde7SWilliam Kucharski 			if (eth_flags & FLAG_PIO)
549*1b8adde7SWilliam Kucharski 				eth_pio_read(pktoff, p, frag);
550*1b8adde7SWilliam Kucharski 			else
551*1b8adde7SWilliam Kucharski 				memcpy(p, bus_to_virt(eth_rmem + pktoff), frag);
552*1b8adde7SWilliam Kucharski 			pktoff = eth_rx_start << 8;
553*1b8adde7SWilliam Kucharski 			p += frag;
554*1b8adde7SWilliam Kucharski 			len -= frag;
555*1b8adde7SWilliam Kucharski 		}
556*1b8adde7SWilliam Kucharski 		/* read second part */
557*1b8adde7SWilliam Kucharski 		if (eth_flags & FLAG_PIO)
558*1b8adde7SWilliam Kucharski 			eth_pio_read(pktoff, p, len);
559*1b8adde7SWilliam Kucharski 		else
560*1b8adde7SWilliam Kucharski 			memcpy(p, bus_to_virt(eth_rmem + pktoff), len);
561*1b8adde7SWilliam Kucharski 		ret = 1;
562*1b8adde7SWilliam Kucharski 	}
563*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_WD
564*1b8adde7SWilliam Kucharski #ifndef	WD_790_PIO
565*1b8adde7SWilliam Kucharski 	if (eth_flags & FLAG_790) {
566*1b8adde7SWilliam Kucharski 		outb(0, eth_asic_base + WD_MSR);
567*1b8adde7SWilliam Kucharski 		inb(0x84);
568*1b8adde7SWilliam Kucharski 	}
569*1b8adde7SWilliam Kucharski #endif
570*1b8adde7SWilliam Kucharski 	if (eth_flags & FLAG_16BIT) {
571*1b8adde7SWilliam Kucharski 		outb(eth_laar & ~WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
572*1b8adde7SWilliam Kucharski 		inb(0x84);
573*1b8adde7SWilliam Kucharski 	}
574*1b8adde7SWilliam Kucharski 	inb(0x84);
575*1b8adde7SWilliam Kucharski #endif
576*1b8adde7SWilliam Kucharski 	next = pkthdr.next;		/* frame number of next packet */
577*1b8adde7SWilliam Kucharski 	if (next == eth_rx_start)
578*1b8adde7SWilliam Kucharski 		next = eth_memsize;
579*1b8adde7SWilliam Kucharski 	outb(next-1, eth_nic_base+D8390_P0_BOUND);
580*1b8adde7SWilliam Kucharski 	return(ret);
581*1b8adde7SWilliam Kucharski }
582*1b8adde7SWilliam Kucharski 
583*1b8adde7SWilliam Kucharski /**************************************************************************
584*1b8adde7SWilliam Kucharski NS8390_DISABLE - Turn off adapter
585*1b8adde7SWilliam Kucharski **************************************************************************/
586*1b8adde7SWilliam Kucharski static void ns8390_disable(struct dev *dev)
587*1b8adde7SWilliam Kucharski {
588*1b8adde7SWilliam Kucharski 	struct nic *nic = (struct nic *)dev;
589*1b8adde7SWilliam Kucharski 	/* reset and disable merge */
590*1b8adde7SWilliam Kucharski 	ns8390_reset(nic);
591*1b8adde7SWilliam Kucharski }
592*1b8adde7SWilliam Kucharski 
593*1b8adde7SWilliam Kucharski /**************************************************************************
594*1b8adde7SWilliam Kucharski NS8390_IRQ - Enable, Disable, or Force interrupts
595*1b8adde7SWilliam Kucharski **************************************************************************/
596*1b8adde7SWilliam Kucharski static void ns8390_irq(struct nic *nic __unused, irq_action_t action __unused)
597*1b8adde7SWilliam Kucharski {
598*1b8adde7SWilliam Kucharski   switch ( action ) {
599*1b8adde7SWilliam Kucharski   case DISABLE :
600*1b8adde7SWilliam Kucharski     break;
601*1b8adde7SWilliam Kucharski   case ENABLE :
602*1b8adde7SWilliam Kucharski     break;
603*1b8adde7SWilliam Kucharski   case FORCE :
604*1b8adde7SWilliam Kucharski     break;
605*1b8adde7SWilliam Kucharski   }
606*1b8adde7SWilliam Kucharski }
607*1b8adde7SWilliam Kucharski 
608*1b8adde7SWilliam Kucharski /**************************************************************************
609*1b8adde7SWilliam Kucharski ETH_PROBE - Look for an adapter
610*1b8adde7SWilliam Kucharski **************************************************************************/
611*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_NS8390
612*1b8adde7SWilliam Kucharski static int eth_probe (struct dev *dev, struct pci_device *pci)
613*1b8adde7SWilliam Kucharski #else
614*1b8adde7SWilliam Kucharski static int eth_probe (struct dev *dev, unsigned short *probe_addrs __unused)
615*1b8adde7SWilliam Kucharski #endif
616*1b8adde7SWilliam Kucharski {
617*1b8adde7SWilliam Kucharski 	struct nic *nic = (struct nic *)dev;
618*1b8adde7SWilliam Kucharski 	int i;
619*1b8adde7SWilliam Kucharski #ifdef INCLUDE_NS8390
620*1b8adde7SWilliam Kucharski 	unsigned short pci_probe_addrs[] = { pci->ioaddr, 0 };
621*1b8adde7SWilliam Kucharski 	unsigned short *probe_addrs = pci_probe_addrs;
622*1b8adde7SWilliam Kucharski #endif
623*1b8adde7SWilliam Kucharski 	eth_vendor = VENDOR_NONE;
624*1b8adde7SWilliam Kucharski 	eth_drain_receiver = 0;
625*1b8adde7SWilliam Kucharski 
626*1b8adde7SWilliam Kucharski 	nic->irqno  = 0;
627*1b8adde7SWilliam Kucharski 
628*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_WD
629*1b8adde7SWilliam Kucharski {
630*1b8adde7SWilliam Kucharski 	/******************************************************************
631*1b8adde7SWilliam Kucharski 	Search for WD/SMC cards
632*1b8adde7SWilliam Kucharski 	******************************************************************/
633*1b8adde7SWilliam Kucharski 	struct wd_board *brd;
634*1b8adde7SWilliam Kucharski 	unsigned short chksum;
635*1b8adde7SWilliam Kucharski 	unsigned char c;
636*1b8adde7SWilliam Kucharski 	for (eth_asic_base = WD_LOW_BASE; eth_asic_base <= WD_HIGH_BASE;
637*1b8adde7SWilliam Kucharski 		eth_asic_base += 0x20) {
638*1b8adde7SWilliam Kucharski 		chksum = 0;
639*1b8adde7SWilliam Kucharski 		for (i=8; i<16; i++)
640*1b8adde7SWilliam Kucharski 			chksum += inb(eth_asic_base+i);
641*1b8adde7SWilliam Kucharski 		/* Extra checks to avoid soundcard */
642*1b8adde7SWilliam Kucharski 		if ((chksum & 0xFF) == 0xFF &&
643*1b8adde7SWilliam Kucharski 			inb(eth_asic_base+8) != 0xFF &&
644*1b8adde7SWilliam Kucharski 			inb(eth_asic_base+9) != 0xFF)
645*1b8adde7SWilliam Kucharski 			break;
646*1b8adde7SWilliam Kucharski 	}
647*1b8adde7SWilliam Kucharski 	if (eth_asic_base > WD_HIGH_BASE)
648*1b8adde7SWilliam Kucharski 		return (0);
649*1b8adde7SWilliam Kucharski 	/* We've found a board */
650*1b8adde7SWilliam Kucharski 	eth_vendor = VENDOR_WD;
651*1b8adde7SWilliam Kucharski 	eth_nic_base = eth_asic_base + WD_NIC_ADDR;
652*1b8adde7SWilliam Kucharski 
653*1b8adde7SWilliam Kucharski 	nic->ioaddr = eth_nic_base;
654*1b8adde7SWilliam Kucharski 
655*1b8adde7SWilliam Kucharski 	c = inb(eth_asic_base+WD_BID);	/* Get board id */
656*1b8adde7SWilliam Kucharski 	for (brd = wd_boards; brd->name; brd++)
657*1b8adde7SWilliam Kucharski 		if (brd->id == c) break;
658*1b8adde7SWilliam Kucharski 	if (!brd->name) {
659*1b8adde7SWilliam Kucharski 		printf("Unknown WD/SMC NIC type %hhX\n", c);
660*1b8adde7SWilliam Kucharski 		return (0);	/* Unknown type */
661*1b8adde7SWilliam Kucharski 	}
662*1b8adde7SWilliam Kucharski 	eth_flags = brd->flags;
663*1b8adde7SWilliam Kucharski 	eth_memsize = brd->memsize;
664*1b8adde7SWilliam Kucharski 	eth_tx_start = 0;
665*1b8adde7SWilliam Kucharski 	eth_rx_start = D8390_TXBUF_SIZE;
666*1b8adde7SWilliam Kucharski 	if ((c == TYPE_WD8013EP) &&
667*1b8adde7SWilliam Kucharski 		(inb(eth_asic_base + WD_ICR) & WD_ICR_16BIT)) {
668*1b8adde7SWilliam Kucharski 			eth_flags = FLAG_16BIT;
669*1b8adde7SWilliam Kucharski 			eth_memsize = MEM_16384;
670*1b8adde7SWilliam Kucharski 	}
671*1b8adde7SWilliam Kucharski 	if ((c & WD_SOFTCONFIG) && (!(eth_flags & FLAG_790))) {
672*1b8adde7SWilliam Kucharski 		eth_bmem = (0x80000 |
673*1b8adde7SWilliam Kucharski 		 ((inb(eth_asic_base + WD_MSR) & 0x3F) << 13));
674*1b8adde7SWilliam Kucharski 	} else
675*1b8adde7SWilliam Kucharski 		eth_bmem = WD_DEFAULT_MEM;
676*1b8adde7SWilliam Kucharski 	if (brd->id == TYPE_SMC8216T || brd->id == TYPE_SMC8216C) {
677*1b8adde7SWilliam Kucharski 		/* from Linux driver, 8416BT detects as 8216 sometimes */
678*1b8adde7SWilliam Kucharski 		unsigned int addr = inb(eth_asic_base + 0xb);
679*1b8adde7SWilliam Kucharski 		if (((addr >> 4) & 3) == 0) {
680*1b8adde7SWilliam Kucharski 			brd += 2;
681*1b8adde7SWilliam Kucharski 			eth_memsize = brd->memsize;
682*1b8adde7SWilliam Kucharski 		}
683*1b8adde7SWilliam Kucharski 	}
684*1b8adde7SWilliam Kucharski 	outb(0x80, eth_asic_base + WD_MSR);	/* Reset */
685*1b8adde7SWilliam Kucharski 	for (i=0; i<ETH_ALEN; i++) {
686*1b8adde7SWilliam Kucharski 		nic->node_addr[i] = inb(i+eth_asic_base+WD_LAR);
687*1b8adde7SWilliam Kucharski 	}
688*1b8adde7SWilliam Kucharski 	printf("\n%s base %#hx", brd->name, eth_asic_base);
689*1b8adde7SWilliam Kucharski 	if (eth_flags & FLAG_790) {
690*1b8adde7SWilliam Kucharski #ifdef	WD_790_PIO
691*1b8adde7SWilliam Kucharski 		printf(", PIO mode, addr %!\n", nic->node_addr);
692*1b8adde7SWilliam Kucharski 		eth_bmem = 0;
693*1b8adde7SWilliam Kucharski 		eth_flags |= FLAG_PIO;		/* force PIO mode */
694*1b8adde7SWilliam Kucharski 		outb(0, eth_asic_base+WD_MSR);
695*1b8adde7SWilliam Kucharski #else
696*1b8adde7SWilliam Kucharski 		printf(", memory %#x, addr %!\n", eth_bmem, nic->node_addr);
697*1b8adde7SWilliam Kucharski 		outb(WD_MSR_MENB, eth_asic_base+WD_MSR);
698*1b8adde7SWilliam Kucharski 		outb((inb(eth_asic_base+0x04) |
699*1b8adde7SWilliam Kucharski 			0x80), eth_asic_base+0x04);
700*1b8adde7SWilliam Kucharski 		outb(((unsigned)(eth_bmem >> 13) & 0x0F) |
701*1b8adde7SWilliam Kucharski 			((unsigned)(eth_bmem >> 11) & 0x40) |
702*1b8adde7SWilliam Kucharski 			(inb(eth_asic_base+0x0B) & 0xB0), eth_asic_base+0x0B);
703*1b8adde7SWilliam Kucharski 		outb((inb(eth_asic_base+0x04) &
704*1b8adde7SWilliam Kucharski 			~0x80), eth_asic_base+0x04);
705*1b8adde7SWilliam Kucharski #endif
706*1b8adde7SWilliam Kucharski 	} else {
707*1b8adde7SWilliam Kucharski 		printf(", memory %#x, addr %!\n", eth_bmem, nic->node_addr);
708*1b8adde7SWilliam Kucharski 		outb(((unsigned)(eth_bmem >> 13) & 0x3F) | 0x40, eth_asic_base+WD_MSR);
709*1b8adde7SWilliam Kucharski 	}
710*1b8adde7SWilliam Kucharski 	if (eth_flags & FLAG_16BIT) {
711*1b8adde7SWilliam Kucharski 		if (eth_flags & FLAG_790) {
712*1b8adde7SWilliam Kucharski 			eth_laar = inb(eth_asic_base + WD_LAAR);
713*1b8adde7SWilliam Kucharski 			outb(WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
714*1b8adde7SWilliam Kucharski 		} else {
715*1b8adde7SWilliam Kucharski 			outb((eth_laar =
716*1b8adde7SWilliam Kucharski 				WD_LAAR_L16EN | 1), eth_asic_base + WD_LAAR);
717*1b8adde7SWilliam Kucharski /*
718*1b8adde7SWilliam Kucharski 	The previous line used to be
719*1b8adde7SWilliam Kucharski 				WD_LAAR_M16EN | WD_LAAR_L16EN | 1));
720*1b8adde7SWilliam Kucharski 	jluke@deakin.edu.au reported that removing WD_LAAR_M16EN made
721*1b8adde7SWilliam Kucharski 	it work for WD8013s.  This seems to work for my 8013 boards. I
722*1b8adde7SWilliam Kucharski 	don't know what is really happening.  I wish I had data sheets
723*1b8adde7SWilliam Kucharski 	or more time to decode the Linux driver. - Ken
724*1b8adde7SWilliam Kucharski */
725*1b8adde7SWilliam Kucharski 		}
726*1b8adde7SWilliam Kucharski 		inb(0x84);
727*1b8adde7SWilliam Kucharski 	}
728*1b8adde7SWilliam Kucharski }
729*1b8adde7SWilliam Kucharski #endif
730*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_3C503
731*1b8adde7SWilliam Kucharski #ifdef	T503_AUI
732*1b8adde7SWilliam Kucharski 	nic->flags = 1;		/* aui */
733*1b8adde7SWilliam Kucharski #else
734*1b8adde7SWilliam Kucharski 	nic->flags = 0;		/* no aui */
735*1b8adde7SWilliam Kucharski #endif
736*1b8adde7SWilliam Kucharski         /******************************************************************
737*1b8adde7SWilliam Kucharski         Search for 3Com 3c503 if no WD/SMC cards
738*1b8adde7SWilliam Kucharski         ******************************************************************/
739*1b8adde7SWilliam Kucharski 	if (eth_vendor == VENDOR_NONE) {
740*1b8adde7SWilliam Kucharski 		int	idx;
741*1b8adde7SWilliam Kucharski 		int	iobase_reg, membase_reg;
742*1b8adde7SWilliam Kucharski 		static unsigned short	base[] = {
743*1b8adde7SWilliam Kucharski 			0x300, 0x310, 0x330, 0x350,
744*1b8adde7SWilliam Kucharski 			0x250, 0x280, 0x2A0, 0x2E0, 0 };
745*1b8adde7SWilliam Kucharski 
746*1b8adde7SWilliam Kucharski 		/* Loop through possible addresses checking each one */
747*1b8adde7SWilliam Kucharski 
748*1b8adde7SWilliam Kucharski 		for (idx = 0; (eth_nic_base = base[idx]) != 0; ++idx) {
749*1b8adde7SWilliam Kucharski 
750*1b8adde7SWilliam Kucharski 			eth_asic_base = eth_nic_base + _3COM_ASIC_OFFSET;
751*1b8adde7SWilliam Kucharski /*
752*1b8adde7SWilliam Kucharski  * Note that we use the same settings for both 8 and 16 bit cards:
753*1b8adde7SWilliam Kucharski  * both have an 8K bank of memory at page 1 while only the 16 bit
754*1b8adde7SWilliam Kucharski  * cards have a bank at page 0.
755*1b8adde7SWilliam Kucharski  */
756*1b8adde7SWilliam Kucharski 			eth_memsize = MEM_16384;
757*1b8adde7SWilliam Kucharski 			eth_tx_start = 32;
758*1b8adde7SWilliam Kucharski 			eth_rx_start = 32 + D8390_TXBUF_SIZE;
759*1b8adde7SWilliam Kucharski 
760*1b8adde7SWilliam Kucharski 		/* Check our base address. iobase and membase should */
761*1b8adde7SWilliam Kucharski 		/* both have a maximum of 1 bit set or be 0. */
762*1b8adde7SWilliam Kucharski 
763*1b8adde7SWilliam Kucharski 			iobase_reg = inb(eth_asic_base + _3COM_BCFR);
764*1b8adde7SWilliam Kucharski 			membase_reg = inb(eth_asic_base + _3COM_PCFR);
765*1b8adde7SWilliam Kucharski 
766*1b8adde7SWilliam Kucharski 			if ((iobase_reg & (iobase_reg - 1)) ||
767*1b8adde7SWilliam Kucharski 				(membase_reg & (membase_reg - 1)))
768*1b8adde7SWilliam Kucharski 				continue;		/* nope */
769*1b8adde7SWilliam Kucharski 
770*1b8adde7SWilliam Kucharski 		/* Now get the shared memory address */
771*1b8adde7SWilliam Kucharski 
772*1b8adde7SWilliam Kucharski 			eth_flags = 0;
773*1b8adde7SWilliam Kucharski 
774*1b8adde7SWilliam Kucharski 			switch (membase_reg) {
775*1b8adde7SWilliam Kucharski 				case _3COM_PCFR_DC000:
776*1b8adde7SWilliam Kucharski 					eth_bmem = 0xdc000;
777*1b8adde7SWilliam Kucharski 					break;
778*1b8adde7SWilliam Kucharski 				case _3COM_PCFR_D8000:
779*1b8adde7SWilliam Kucharski 					eth_bmem = 0xd8000;
780*1b8adde7SWilliam Kucharski 					break;
781*1b8adde7SWilliam Kucharski 				case _3COM_PCFR_CC000:
782*1b8adde7SWilliam Kucharski 					eth_bmem = 0xcc000;
783*1b8adde7SWilliam Kucharski 					break;
784*1b8adde7SWilliam Kucharski 				case _3COM_PCFR_C8000:
785*1b8adde7SWilliam Kucharski 					eth_bmem = 0xc8000;
786*1b8adde7SWilliam Kucharski 					break;
787*1b8adde7SWilliam Kucharski 				case _3COM_PCFR_PIO:
788*1b8adde7SWilliam Kucharski 					eth_flags |= FLAG_PIO;
789*1b8adde7SWilliam Kucharski 					eth_bmem = 0;
790*1b8adde7SWilliam Kucharski 					break;
791*1b8adde7SWilliam Kucharski 				default:
792*1b8adde7SWilliam Kucharski 					continue;	/* nope */
793*1b8adde7SWilliam Kucharski 				}
794*1b8adde7SWilliam Kucharski 			break;
795*1b8adde7SWilliam Kucharski 		}
796*1b8adde7SWilliam Kucharski 
797*1b8adde7SWilliam Kucharski 		if (base[idx] == 0)		/* not found */
798*1b8adde7SWilliam Kucharski 			return (0);
799*1b8adde7SWilliam Kucharski #ifndef	T503_SHMEM
800*1b8adde7SWilliam Kucharski 		eth_flags |= FLAG_PIO;		/* force PIO mode */
801*1b8adde7SWilliam Kucharski 		eth_bmem = 0;
802*1b8adde7SWilliam Kucharski #endif
803*1b8adde7SWilliam Kucharski 		eth_vendor = VENDOR_3COM;
804*1b8adde7SWilliam Kucharski 
805*1b8adde7SWilliam Kucharski 
806*1b8adde7SWilliam Kucharski         /* Need this to make ns8390_poll() happy. */
807*1b8adde7SWilliam Kucharski 
808*1b8adde7SWilliam Kucharski                 eth_rmem = eth_bmem - 0x2000;
809*1b8adde7SWilliam Kucharski 
810*1b8adde7SWilliam Kucharski         /* Reset NIC and ASIC */
811*1b8adde7SWilliam Kucharski 
812*1b8adde7SWilliam Kucharski                 outb(_3COM_CR_RST | _3COM_CR_XSEL, eth_asic_base + _3COM_CR );
813*1b8adde7SWilliam Kucharski                 outb(_3COM_CR_XSEL, eth_asic_base + _3COM_CR );
814*1b8adde7SWilliam Kucharski 
815*1b8adde7SWilliam Kucharski         /* Get our ethernet address */
816*1b8adde7SWilliam Kucharski 
817*1b8adde7SWilliam Kucharski                 outb(_3COM_CR_EALO | _3COM_CR_XSEL, eth_asic_base + _3COM_CR);
818*1b8adde7SWilliam Kucharski 		nic->ioaddr = eth_nic_base;
819*1b8adde7SWilliam Kucharski                 printf("\n3Com 3c503 base %#hx, ", eth_nic_base);
820*1b8adde7SWilliam Kucharski                 if (eth_flags & FLAG_PIO)
821*1b8adde7SWilliam Kucharski 			printf("PIO mode");
822*1b8adde7SWilliam Kucharski                 else
823*1b8adde7SWilliam Kucharski 			printf("memory %#x", eth_bmem);
824*1b8adde7SWilliam Kucharski                 for (i=0; i<ETH_ALEN; i++) {
825*1b8adde7SWilliam Kucharski                         nic->node_addr[i] = inb(eth_nic_base+i);
826*1b8adde7SWilliam Kucharski                 }
827*1b8adde7SWilliam Kucharski                 printf(", %s, addr %!\n", nic->flags ? "AUI" : "internal xcvr",
828*1b8adde7SWilliam Kucharski 			nic->node_addr);
829*1b8adde7SWilliam Kucharski                 outb(_3COM_CR_XSEL, eth_asic_base + _3COM_CR);
830*1b8adde7SWilliam Kucharski         /*
831*1b8adde7SWilliam Kucharski          * Initialize GA configuration register. Set bank and enable shared
832*1b8adde7SWilliam Kucharski          * mem. We always use bank 1. Disable interrupts.
833*1b8adde7SWilliam Kucharski          */
834*1b8adde7SWilliam Kucharski                 outb(_3COM_GACFR_RSEL |
835*1b8adde7SWilliam Kucharski 			_3COM_GACFR_MBS0 | _3COM_GACFR_TCM | _3COM_GACFR_NIM, eth_asic_base + _3COM_GACFR);
836*1b8adde7SWilliam Kucharski 
837*1b8adde7SWilliam Kucharski                 outb(0xff, eth_asic_base + _3COM_VPTR2);
838*1b8adde7SWilliam Kucharski                 outb(0xff, eth_asic_base + _3COM_VPTR1);
839*1b8adde7SWilliam Kucharski                 outb(0x00, eth_asic_base + _3COM_VPTR0);
840*1b8adde7SWilliam Kucharski         /*
841*1b8adde7SWilliam Kucharski          * Clear memory and verify that it worked (we use only 8K)
842*1b8adde7SWilliam Kucharski          */
843*1b8adde7SWilliam Kucharski 
844*1b8adde7SWilliam Kucharski 		if (!(eth_flags & FLAG_PIO)) {
845*1b8adde7SWilliam Kucharski 			memset(bus_to_virt(eth_bmem), 0, 0x2000);
846*1b8adde7SWilliam Kucharski 			for(i = 0; i < 0x2000; ++i)
847*1b8adde7SWilliam Kucharski 				if (*((char *)(bus_to_virt(eth_bmem+i)))) {
848*1b8adde7SWilliam Kucharski 					printf ("Failed to clear 3c503 shared mem.\n");
849*1b8adde7SWilliam Kucharski 					return (0);
850*1b8adde7SWilliam Kucharski 				}
851*1b8adde7SWilliam Kucharski 		}
852*1b8adde7SWilliam Kucharski         /*
853*1b8adde7SWilliam Kucharski          * Initialize GA page/start/stop registers.
854*1b8adde7SWilliam Kucharski          */
855*1b8adde7SWilliam Kucharski                 outb(eth_tx_start, eth_asic_base + _3COM_PSTR);
856*1b8adde7SWilliam Kucharski                 outb(eth_memsize, eth_asic_base + _3COM_PSPR);
857*1b8adde7SWilliam Kucharski         }
858*1b8adde7SWilliam Kucharski #endif
859*1b8adde7SWilliam Kucharski #if	defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
860*1b8adde7SWilliam Kucharski {
861*1b8adde7SWilliam Kucharski 	/******************************************************************
862*1b8adde7SWilliam Kucharski 	Search for NE1000/2000 if no WD/SMC or 3com cards
863*1b8adde7SWilliam Kucharski 	******************************************************************/
864*1b8adde7SWilliam Kucharski 	unsigned char c;
865*1b8adde7SWilliam Kucharski 	if (eth_vendor == VENDOR_NONE) {
866*1b8adde7SWilliam Kucharski 		char romdata[16], testbuf[32];
867*1b8adde7SWilliam Kucharski 		int idx;
868*1b8adde7SWilliam Kucharski 		static char test[] = "NE*000 memory";
869*1b8adde7SWilliam Kucharski 		static unsigned short base[] = {
870*1b8adde7SWilliam Kucharski #ifdef	NE_SCAN
871*1b8adde7SWilliam Kucharski 			NE_SCAN,
872*1b8adde7SWilliam Kucharski #endif
873*1b8adde7SWilliam Kucharski 			0 };
874*1b8adde7SWilliam Kucharski 		/* if no addresses supplied, fall back on defaults */
875*1b8adde7SWilliam Kucharski 		if (probe_addrs == 0 || probe_addrs[0] == 0)
876*1b8adde7SWilliam Kucharski 			probe_addrs = base;
877*1b8adde7SWilliam Kucharski 		eth_bmem = 0;		/* No shared memory */
878*1b8adde7SWilliam Kucharski 		for (idx = 0; (eth_nic_base = probe_addrs[idx]) != 0; ++idx) {
879*1b8adde7SWilliam Kucharski 			eth_flags = FLAG_PIO;
880*1b8adde7SWilliam Kucharski 			eth_asic_base = eth_nic_base + NE_ASIC_OFFSET;
881*1b8adde7SWilliam Kucharski 			eth_memsize = MEM_16384;
882*1b8adde7SWilliam Kucharski 			eth_tx_start = 32;
883*1b8adde7SWilliam Kucharski 			eth_rx_start = 32 + D8390_TXBUF_SIZE;
884*1b8adde7SWilliam Kucharski 			c = inb(eth_asic_base + NE_RESET);
885*1b8adde7SWilliam Kucharski 			outb(c, eth_asic_base + NE_RESET);
886*1b8adde7SWilliam Kucharski 			inb(0x84);
887*1b8adde7SWilliam Kucharski 			outb(D8390_COMMAND_STP |
888*1b8adde7SWilliam Kucharski 				D8390_COMMAND_RD2, eth_nic_base + D8390_P0_COMMAND);
889*1b8adde7SWilliam Kucharski 			outb(D8390_RCR_MON, eth_nic_base + D8390_P0_RCR);
890*1b8adde7SWilliam Kucharski 			outb(D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
891*1b8adde7SWilliam Kucharski 			outb(MEM_8192, eth_nic_base + D8390_P0_PSTART);
892*1b8adde7SWilliam Kucharski 			outb(MEM_16384, eth_nic_base + D8390_P0_PSTOP);
893*1b8adde7SWilliam Kucharski #ifdef	NS8390_FORCE_16BIT
894*1b8adde7SWilliam Kucharski 			eth_flags |= FLAG_16BIT;	/* force 16-bit mode */
895*1b8adde7SWilliam Kucharski #endif
896*1b8adde7SWilliam Kucharski 
897*1b8adde7SWilliam Kucharski 			eth_pio_write(test, 8192, sizeof(test));
898*1b8adde7SWilliam Kucharski 			eth_pio_read(8192, testbuf, sizeof(test));
899*1b8adde7SWilliam Kucharski 			if (!memcmp(test, testbuf, sizeof(test)))
900*1b8adde7SWilliam Kucharski 				break;
901*1b8adde7SWilliam Kucharski 			eth_flags |= FLAG_16BIT;
902*1b8adde7SWilliam Kucharski 			eth_memsize = MEM_32768;
903*1b8adde7SWilliam Kucharski 			eth_tx_start = 64;
904*1b8adde7SWilliam Kucharski 			eth_rx_start = 64 + D8390_TXBUF_SIZE;
905*1b8adde7SWilliam Kucharski 			outb(D8390_DCR_WTS |
906*1b8adde7SWilliam Kucharski 				D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
907*1b8adde7SWilliam Kucharski 			outb(MEM_16384, eth_nic_base + D8390_P0_PSTART);
908*1b8adde7SWilliam Kucharski 			outb(MEM_32768, eth_nic_base + D8390_P0_PSTOP);
909*1b8adde7SWilliam Kucharski 			eth_pio_write(test, 16384, sizeof(test));
910*1b8adde7SWilliam Kucharski 			eth_pio_read(16384, testbuf, sizeof(test));
911*1b8adde7SWilliam Kucharski 			if (!memcmp(testbuf, test, sizeof(test)))
912*1b8adde7SWilliam Kucharski 				break;
913*1b8adde7SWilliam Kucharski 		}
914*1b8adde7SWilliam Kucharski 		if (eth_nic_base == 0)
915*1b8adde7SWilliam Kucharski 			return (0);
916*1b8adde7SWilliam Kucharski 		if (eth_nic_base > ISA_MAX_ADDR)	/* PCI probably */
917*1b8adde7SWilliam Kucharski 			eth_flags |= FLAG_16BIT;
918*1b8adde7SWilliam Kucharski 		eth_vendor = VENDOR_NOVELL;
919*1b8adde7SWilliam Kucharski 		eth_pio_read(0, romdata, sizeof(romdata));
920*1b8adde7SWilliam Kucharski 		for (i=0; i<ETH_ALEN; i++) {
921*1b8adde7SWilliam Kucharski 			nic->node_addr[i] = romdata[i + ((eth_flags & FLAG_16BIT) ? i : 0)];
922*1b8adde7SWilliam Kucharski 		}
923*1b8adde7SWilliam Kucharski 		nic->ioaddr = eth_nic_base;
924*1b8adde7SWilliam Kucharski 		printf("\nNE%c000 base %#hx, addr %!\n",
925*1b8adde7SWilliam Kucharski 			(eth_flags & FLAG_16BIT) ? '2' : '1', eth_nic_base,
926*1b8adde7SWilliam Kucharski 			nic->node_addr);
927*1b8adde7SWilliam Kucharski 	}
928*1b8adde7SWilliam Kucharski }
929*1b8adde7SWilliam Kucharski #endif
930*1b8adde7SWilliam Kucharski 	if (eth_vendor == VENDOR_NONE)
931*1b8adde7SWilliam Kucharski 		return(0);
932*1b8adde7SWilliam Kucharski         if (eth_vendor != VENDOR_3COM)
933*1b8adde7SWilliam Kucharski 		eth_rmem = eth_bmem;
934*1b8adde7SWilliam Kucharski 	ns8390_reset(nic);
935*1b8adde7SWilliam Kucharski 
936*1b8adde7SWilliam Kucharski 	dev->disable  = ns8390_disable;
937*1b8adde7SWilliam Kucharski 	nic->poll     = ns8390_poll;
938*1b8adde7SWilliam Kucharski 	nic->transmit = ns8390_transmit;
939*1b8adde7SWilliam Kucharski 	nic->irq      = ns8390_irq;
940*1b8adde7SWilliam Kucharski 
941*1b8adde7SWilliam Kucharski         /* Based on PnP ISA map */
942*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_WD
943*1b8adde7SWilliam Kucharski         dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
944*1b8adde7SWilliam Kucharski         dev->devid.device_id = htons(0x812a);
945*1b8adde7SWilliam Kucharski #endif
946*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_3C503
947*1b8adde7SWilliam Kucharski         dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
948*1b8adde7SWilliam Kucharski         dev->devid.device_id = htons(0x80f3);
949*1b8adde7SWilliam Kucharski #endif
950*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_NE
951*1b8adde7SWilliam Kucharski         dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
952*1b8adde7SWilliam Kucharski         dev->devid.device_id = htons(0x80d6);
953*1b8adde7SWilliam Kucharski #endif
954*1b8adde7SWilliam Kucharski 	return 1;
955*1b8adde7SWilliam Kucharski }
956*1b8adde7SWilliam Kucharski 
957*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_WD
958*1b8adde7SWilliam Kucharski static struct isa_driver wd_driver __isa_driver = {
959*1b8adde7SWilliam Kucharski 	.type    = NIC_DRIVER,
960*1b8adde7SWilliam Kucharski 	.name    = "WD",
961*1b8adde7SWilliam Kucharski 	.probe   = wd_probe,
962*1b8adde7SWilliam Kucharski 	.ioaddrs = 0,
963*1b8adde7SWilliam Kucharski };
964*1b8adde7SWilliam Kucharski #endif
965*1b8adde7SWilliam Kucharski 
966*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_3C503
967*1b8adde7SWilliam Kucharski static struct isa_driver t503_driver __isa_driver = {
968*1b8adde7SWilliam Kucharski 	.type    = NIC_DRIVER,
969*1b8adde7SWilliam Kucharski 	.name    = "3C503",
970*1b8adde7SWilliam Kucharski 	.probe   = t503_probe,
971*1b8adde7SWilliam Kucharski 	.ioaddrs = 0,
972*1b8adde7SWilliam Kucharski };
973*1b8adde7SWilliam Kucharski #endif
974*1b8adde7SWilliam Kucharski 
975*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_NE
976*1b8adde7SWilliam Kucharski static struct isa_driver ne_driver __isa_driver = {
977*1b8adde7SWilliam Kucharski 	.type    = NIC_DRIVER,
978*1b8adde7SWilliam Kucharski 	.name    = "NE*000",
979*1b8adde7SWilliam Kucharski 	.probe   = ne_probe,
980*1b8adde7SWilliam Kucharski 	.ioaddrs = 0,
981*1b8adde7SWilliam Kucharski };
982*1b8adde7SWilliam Kucharski #endif
983*1b8adde7SWilliam Kucharski 
984*1b8adde7SWilliam Kucharski #ifdef	INCLUDE_NS8390
985*1b8adde7SWilliam Kucharski static struct pci_id nepci_nics[] = {
986*1b8adde7SWilliam Kucharski /* A few NE2000 PCI clones, list not exhaustive */
987*1b8adde7SWilliam Kucharski PCI_ROM(0x10ec, 0x8029, "rtl8029",      "Realtek 8029"),
988*1b8adde7SWilliam Kucharski PCI_ROM(0x1186, 0x0300, "dlink-528",    "D-Link DE-528"),
989*1b8adde7SWilliam Kucharski PCI_ROM(0x1050, 0x0940, "winbond940",   "Winbond NE2000-PCI"),		/* Winbond 86C940 / 89C940 */
990*1b8adde7SWilliam Kucharski PCI_ROM(0x1050, 0x5a5a, "winbond940f",  "Winbond W89c940F"),		/* Winbond 89C940F */
991*1b8adde7SWilliam Kucharski PCI_ROM(0x11f6, 0x1401, "compexrl2000", "Compex ReadyLink 2000"),
992*1b8adde7SWilliam Kucharski PCI_ROM(0x8e2e, 0x3000, "ktiet32p2",    "KTI ET32P2"),
993*1b8adde7SWilliam Kucharski PCI_ROM(0x4a14, 0x5000, "nv5000sc",     "NetVin NV5000SC"),
994*1b8adde7SWilliam Kucharski PCI_ROM(0x12c3, 0x0058, "holtek80232",  "Holtek HT80232"),
995*1b8adde7SWilliam Kucharski PCI_ROM(0x12c3, 0x5598, "holtek80229",  "Holtek HT80229"),
996*1b8adde7SWilliam Kucharski PCI_ROM(0x10bd, 0x0e34, "surecom-ne34", "Surecom NE34"),
997*1b8adde7SWilliam Kucharski PCI_ROM(0x1106, 0x0926, "via86c926",    "Via 86c926"),
998*1b8adde7SWilliam Kucharski };
999*1b8adde7SWilliam Kucharski 
1000*1b8adde7SWilliam Kucharski struct pci_driver nepci_driver = {
1001*1b8adde7SWilliam Kucharski 	.type     = NIC_DRIVER,
1002*1b8adde7SWilliam Kucharski 	.name     = "NE2000/PCI",
1003*1b8adde7SWilliam Kucharski 	.probe    = nepci_probe,
1004*1b8adde7SWilliam Kucharski 	.ids      = nepci_nics,
1005*1b8adde7SWilliam Kucharski 	.id_count = sizeof(nepci_nics)/sizeof(nepci_nics[0]),
1006*1b8adde7SWilliam Kucharski 	.class    = 0,
1007*1b8adde7SWilliam Kucharski };
1008*1b8adde7SWilliam Kucharski 
1009*1b8adde7SWilliam Kucharski #endif /* INCLUDE_NS8390 */
1010*1b8adde7SWilliam Kucharski 
1011*1b8adde7SWilliam Kucharski /*
1012*1b8adde7SWilliam Kucharski  * Local variables:
1013*1b8adde7SWilliam Kucharski  *  c-basic-offset: 8
1014*1b8adde7SWilliam Kucharski  * End:
1015*1b8adde7SWilliam Kucharski  */
1016*1b8adde7SWilliam Kucharski 
1017