xref: /minix3/minix/drivers/net/dp8390/ne2000.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc /*
2*433d6423SLionel Sambuc ne2000.c
3*433d6423SLionel Sambuc 
4*433d6423SLionel Sambuc Driver for the ne2000 ethernet cards. This file contains only the ne2000
5*433d6423SLionel Sambuc specific code, the rest is in dp8390.c
6*433d6423SLionel Sambuc 
7*433d6423SLionel Sambuc Created:	March 15, 1994 by Philip Homburg <philip@f-mnx.phicoh.com>
8*433d6423SLionel Sambuc */
9*433d6423SLionel Sambuc 
10*433d6423SLionel Sambuc #include <minix/drivers.h>
11*433d6423SLionel Sambuc 
12*433d6423SLionel Sambuc #include <net/gen/ether.h>
13*433d6423SLionel Sambuc #include <net/gen/eth_io.h>
14*433d6423SLionel Sambuc #if __minix_vmd
15*433d6423SLionel Sambuc #include "config.h"
16*433d6423SLionel Sambuc #endif
17*433d6423SLionel Sambuc 
18*433d6423SLionel Sambuc #include "local.h"
19*433d6423SLionel Sambuc #include "dp8390.h"
20*433d6423SLionel Sambuc #include "ne2000.h"
21*433d6423SLionel Sambuc 
22*433d6423SLionel Sambuc #if ENABLE_NE2000
23*433d6423SLionel Sambuc 
24*433d6423SLionel Sambuc #define N 100
25*433d6423SLionel Sambuc 
26*433d6423SLionel Sambuc extern u32_t system_hz;
27*433d6423SLionel Sambuc 
28*433d6423SLionel Sambuc #define MILLIS_TO_TICKS(m)  (((m)*system_hz/1000)+1)
29*433d6423SLionel Sambuc 
30*433d6423SLionel Sambuc typedef int(*testf_t) (dpeth_t *dep, int pos, u8_t *pat);
31*433d6423SLionel Sambuc 
32*433d6423SLionel Sambuc static u8_t	pat0[]= { 0x00, 0x00, 0x00, 0x00 };
33*433d6423SLionel Sambuc static u8_t	pat1[]= { 0xFF, 0xFF, 0xFF, 0xFF };
34*433d6423SLionel Sambuc static u8_t	pat2[]= { 0xA5, 0x5A, 0x69, 0x96 };
35*433d6423SLionel Sambuc static u8_t	pat3[]= { 0x96, 0x69, 0x5A, 0xA5 };
36*433d6423SLionel Sambuc 
37*433d6423SLionel Sambuc static int test_8(dpeth_t *dep, int pos, u8_t *pat);
38*433d6423SLionel Sambuc static int test_16(dpeth_t *dep, int pos, u8_t *pat);
39*433d6423SLionel Sambuc static void ne_stop(dpeth_t *dep);
40*433d6423SLionel Sambuc static void milli_delay(unsigned long millis);
41*433d6423SLionel Sambuc 
42*433d6423SLionel Sambuc /*===========================================================================*
43*433d6423SLionel Sambuc  *				ne_probe				     *
44*433d6423SLionel Sambuc  *===========================================================================*/
45*433d6423SLionel Sambuc int ne_probe(dpeth_t *dep)
46*433d6423SLionel Sambuc {
47*433d6423SLionel Sambuc 	int byte;
48*433d6423SLionel Sambuc 	int i;
49*433d6423SLionel Sambuc 	int loc1, loc2;
50*433d6423SLionel Sambuc 	testf_t f;
51*433d6423SLionel Sambuc 
52*433d6423SLionel Sambuc 	dep->de_dp8390_port= dep->de_base_port + NE_DP8390;
53*433d6423SLionel Sambuc 
54*433d6423SLionel Sambuc 	/* We probe for an ne1000 or an ne2000 by testing whether the
55*433d6423SLionel Sambuc 	 * on board is reachable through the dp8390. Note that the
56*433d6423SLionel Sambuc 	 * ne1000 is an 8bit card and has a memory region distict from
57*433d6423SLionel Sambuc 	 * the 16bit ne2000
58*433d6423SLionel Sambuc 	 */
59*433d6423SLionel Sambuc 
60*433d6423SLionel Sambuc 	for (dep->de_16bit= 0; dep->de_16bit < 2; dep->de_16bit++)
61*433d6423SLionel Sambuc 	{
62*433d6423SLionel Sambuc 		/* Reset the ethernet card */
63*433d6423SLionel Sambuc 		byte= inb_ne(dep, NE_RESET);
64*433d6423SLionel Sambuc 		milli_delay(2);
65*433d6423SLionel Sambuc 		outb_ne(dep, NE_RESET, byte);
66*433d6423SLionel Sambuc 		milli_delay(2);
67*433d6423SLionel Sambuc 
68*433d6423SLionel Sambuc 		/* Reset the dp8390 */
69*433d6423SLionel Sambuc 		outb_reg0(dep, DP_CR, CR_STP | CR_DM_ABORT);
70*433d6423SLionel Sambuc 		for (i= 0; i < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RST) == 0); i++)
71*433d6423SLionel Sambuc 			; /* Do nothing */
72*433d6423SLionel Sambuc 
73*433d6423SLionel Sambuc 		/* Check if the dp8390 is really there */
74*433d6423SLionel Sambuc 		if ((inb_reg0(dep, DP_CR) & (CR_STP|CR_DM_ABORT)) !=
75*433d6423SLionel Sambuc 			(CR_STP|CR_DM_ABORT))
76*433d6423SLionel Sambuc 		{
77*433d6423SLionel Sambuc 			return 0;
78*433d6423SLionel Sambuc 		}
79*433d6423SLionel Sambuc 
80*433d6423SLionel Sambuc 		/* Disable the receiver and init TCR and DCR. */
81*433d6423SLionel Sambuc 		outb_reg0(dep, DP_RCR, RCR_MON);
82*433d6423SLionel Sambuc 		outb_reg0(dep, DP_TCR, TCR_NORMAL);
83*433d6423SLionel Sambuc 		if (dep->de_16bit)
84*433d6423SLionel Sambuc 		{
85*433d6423SLionel Sambuc 			outb_reg0(dep, DP_DCR, DCR_WORDWIDE | DCR_8BYTES |
86*433d6423SLionel Sambuc 				DCR_BMS);
87*433d6423SLionel Sambuc 		}
88*433d6423SLionel Sambuc 		else
89*433d6423SLionel Sambuc 		{
90*433d6423SLionel Sambuc 			outb_reg0(dep, DP_DCR, DCR_BYTEWIDE | DCR_8BYTES |
91*433d6423SLionel Sambuc 				DCR_BMS);
92*433d6423SLionel Sambuc 		}
93*433d6423SLionel Sambuc 
94*433d6423SLionel Sambuc 		if (dep->de_16bit)
95*433d6423SLionel Sambuc 		{
96*433d6423SLionel Sambuc 			loc1= NE2000_START;
97*433d6423SLionel Sambuc 			loc2= NE2000_START + NE2000_SIZE - 4;
98*433d6423SLionel Sambuc 			f= test_16;
99*433d6423SLionel Sambuc 		}
100*433d6423SLionel Sambuc 		else
101*433d6423SLionel Sambuc 		{
102*433d6423SLionel Sambuc 			loc1= NE1000_START;
103*433d6423SLionel Sambuc 			loc2= NE1000_START + NE1000_SIZE - 4;
104*433d6423SLionel Sambuc 			f= test_8;
105*433d6423SLionel Sambuc 		}
106*433d6423SLionel Sambuc 		if (f(dep, loc1, pat0) && f(dep, loc1, pat1) &&
107*433d6423SLionel Sambuc 			f(dep, loc1, pat2) && f(dep, loc1, pat3) &&
108*433d6423SLionel Sambuc 			f(dep, loc2, pat0) && f(dep, loc2, pat1) &&
109*433d6423SLionel Sambuc 			f(dep, loc2, pat2) && f(dep, loc2, pat3))
110*433d6423SLionel Sambuc 		{
111*433d6423SLionel Sambuc 			/* We don't need a memory segment */
112*433d6423SLionel Sambuc 			dep->de_linmem= 0;
113*433d6423SLionel Sambuc 			if (!dep->de_pci)
114*433d6423SLionel Sambuc 				dep->de_initf= ne_init;
115*433d6423SLionel Sambuc 			dep->de_stopf= ne_stop;
116*433d6423SLionel Sambuc 			dep->de_prog_IO= 1;
117*433d6423SLionel Sambuc 			return 1;
118*433d6423SLionel Sambuc 		}
119*433d6423SLionel Sambuc 	}
120*433d6423SLionel Sambuc 	return 0;
121*433d6423SLionel Sambuc }
122*433d6423SLionel Sambuc 
123*433d6423SLionel Sambuc /*===========================================================================*
124*433d6423SLionel Sambuc  *				ne_init					     *
125*433d6423SLionel Sambuc  *===========================================================================*/
126*433d6423SLionel Sambuc void ne_init(dep)
127*433d6423SLionel Sambuc dpeth_t *dep;
128*433d6423SLionel Sambuc {
129*433d6423SLionel Sambuc 	int i;
130*433d6423SLionel Sambuc 	int word, sendq_nr;
131*433d6423SLionel Sambuc 
132*433d6423SLionel Sambuc 	/* Setup a transfer to get the ethernet address. */
133*433d6423SLionel Sambuc 	if (dep->de_16bit)
134*433d6423SLionel Sambuc 		outb_reg0(dep, DP_RBCR0, 6*2);
135*433d6423SLionel Sambuc 	else
136*433d6423SLionel Sambuc 		outb_reg0(dep, DP_RBCR0, 6);
137*433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR1, 0);
138*433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR0, 0);
139*433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR1, 0);
140*433d6423SLionel Sambuc 	outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
141*433d6423SLionel Sambuc 
142*433d6423SLionel Sambuc 	for (i= 0; i<6; i++)
143*433d6423SLionel Sambuc 	{
144*433d6423SLionel Sambuc 		if (dep->de_16bit)
145*433d6423SLionel Sambuc 		{
146*433d6423SLionel Sambuc 			word= inw_ne(dep, NE_DATA);
147*433d6423SLionel Sambuc 			dep->de_address.ea_addr[i]= word;
148*433d6423SLionel Sambuc 		}
149*433d6423SLionel Sambuc 		else
150*433d6423SLionel Sambuc 		{
151*433d6423SLionel Sambuc 			dep->de_address.ea_addr[i] = inb_ne(dep, NE_DATA);
152*433d6423SLionel Sambuc 		}
153*433d6423SLionel Sambuc 	}
154*433d6423SLionel Sambuc 	dep->de_data_port= dep->de_base_port + NE_DATA;
155*433d6423SLionel Sambuc 	if (dep->de_16bit)
156*433d6423SLionel Sambuc 	{
157*433d6423SLionel Sambuc 		dep->de_ramsize= NE2000_SIZE;
158*433d6423SLionel Sambuc 		dep->de_offset_page= NE2000_START / DP_PAGESIZE;
159*433d6423SLionel Sambuc 	}
160*433d6423SLionel Sambuc 	else
161*433d6423SLionel Sambuc 	{
162*433d6423SLionel Sambuc 		dep->de_ramsize= NE1000_SIZE;
163*433d6423SLionel Sambuc 		dep->de_offset_page= NE1000_START / DP_PAGESIZE;
164*433d6423SLionel Sambuc 	}
165*433d6423SLionel Sambuc 
166*433d6423SLionel Sambuc 	/* Allocate one send buffer (1.5KB) per 8KB of on board memory. */
167*433d6423SLionel Sambuc 	sendq_nr= dep->de_ramsize / 0x2000;
168*433d6423SLionel Sambuc 	if (sendq_nr < 1)
169*433d6423SLionel Sambuc 		sendq_nr= 1;
170*433d6423SLionel Sambuc 	else if (sendq_nr > SENDQ_NR)
171*433d6423SLionel Sambuc 		sendq_nr= SENDQ_NR;
172*433d6423SLionel Sambuc 	dep->de_sendq_nr= sendq_nr;
173*433d6423SLionel Sambuc 	for (i= 0; i<sendq_nr; i++)
174*433d6423SLionel Sambuc 	{
175*433d6423SLionel Sambuc 		dep->de_sendq[i].sq_sendpage= dep->de_offset_page +
176*433d6423SLionel Sambuc 			i*SENDQ_PAGES;
177*433d6423SLionel Sambuc 	}
178*433d6423SLionel Sambuc 
179*433d6423SLionel Sambuc 	dep->de_startpage= dep->de_offset_page + i*SENDQ_PAGES;
180*433d6423SLionel Sambuc 	dep->de_stoppage= dep->de_offset_page + dep->de_ramsize / DP_PAGESIZE;
181*433d6423SLionel Sambuc 
182*433d6423SLionel Sambuc 	/* Can't override the default IRQ. */
183*433d6423SLionel Sambuc 	dep->de_irq &= ~DEI_DEFAULT;
184*433d6423SLionel Sambuc 
185*433d6423SLionel Sambuc 	if (!debug)
186*433d6423SLionel Sambuc 	{
187*433d6423SLionel Sambuc 		printf("%s: NE%d000 at %X:%d\n",
188*433d6423SLionel Sambuc 			dep->de_name, dep->de_16bit ? 2 : 1,
189*433d6423SLionel Sambuc 			dep->de_base_port, dep->de_irq);
190*433d6423SLionel Sambuc 	}
191*433d6423SLionel Sambuc 	else
192*433d6423SLionel Sambuc 	{
193*433d6423SLionel Sambuc 		printf("%s: Novell NE%d000 ethernet card at I/O address "
194*433d6423SLionel Sambuc 			"0x%X, memory size 0x%X, irq %d\n",
195*433d6423SLionel Sambuc 			dep->de_name, dep->de_16bit ? 2 : 1,
196*433d6423SLionel Sambuc 			dep->de_base_port, dep->de_ramsize, dep->de_irq);
197*433d6423SLionel Sambuc 	}
198*433d6423SLionel Sambuc }
199*433d6423SLionel Sambuc 
200*433d6423SLionel Sambuc /*===========================================================================*
201*433d6423SLionel Sambuc  *				test_8					     *
202*433d6423SLionel Sambuc  *===========================================================================*/
203*433d6423SLionel Sambuc static int test_8(dep, pos, pat)
204*433d6423SLionel Sambuc dpeth_t *dep;
205*433d6423SLionel Sambuc int pos;
206*433d6423SLionel Sambuc u8_t *pat;
207*433d6423SLionel Sambuc {
208*433d6423SLionel Sambuc 	u8_t buf[4];
209*433d6423SLionel Sambuc 	int i;
210*433d6423SLionel Sambuc 	int r;
211*433d6423SLionel Sambuc 
212*433d6423SLionel Sambuc 	outb_reg0(dep, DP_ISR, 0xFF);
213*433d6423SLionel Sambuc 
214*433d6423SLionel Sambuc 	/* Setup a transfer to put the pattern. */
215*433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR0, 4);
216*433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR1, 0);
217*433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR0, pos & 0xFF);
218*433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR1, pos >> 8);
219*433d6423SLionel Sambuc 	outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
220*433d6423SLionel Sambuc 
221*433d6423SLionel Sambuc 	for (i= 0; i<4; i++)
222*433d6423SLionel Sambuc 		outb_ne(dep, NE_DATA, pat[i]);
223*433d6423SLionel Sambuc 
224*433d6423SLionel Sambuc 	for (i= 0; i<N; i++)
225*433d6423SLionel Sambuc 	{
226*433d6423SLionel Sambuc 		if (inb_reg0(dep, DP_ISR) & ISR_RDC)
227*433d6423SLionel Sambuc 			break;
228*433d6423SLionel Sambuc 	}
229*433d6423SLionel Sambuc 	if (i == N)
230*433d6423SLionel Sambuc 	{
231*433d6423SLionel Sambuc 		if (debug)
232*433d6423SLionel Sambuc 		{
233*433d6423SLionel Sambuc 			printf("%s: NE1000 remote DMA test failed\n",
234*433d6423SLionel Sambuc 				dep->de_name);
235*433d6423SLionel Sambuc 		}
236*433d6423SLionel Sambuc 		return 0;
237*433d6423SLionel Sambuc 	}
238*433d6423SLionel Sambuc 
239*433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR0, 4);
240*433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR1, 0);
241*433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR0, pos & 0xFF);
242*433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR1, pos >> 8);
243*433d6423SLionel Sambuc 	outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
244*433d6423SLionel Sambuc 
245*433d6423SLionel Sambuc 	for (i= 0; i<4; i++)
246*433d6423SLionel Sambuc 		buf[i]= inb_ne(dep, NE_DATA);
247*433d6423SLionel Sambuc 
248*433d6423SLionel Sambuc 	r= (memcmp(buf, pat, 4) == 0);
249*433d6423SLionel Sambuc 	return r;
250*433d6423SLionel Sambuc }
251*433d6423SLionel Sambuc 
252*433d6423SLionel Sambuc /*===========================================================================*
253*433d6423SLionel Sambuc  *				test_16					     *
254*433d6423SLionel Sambuc  *===========================================================================*/
255*433d6423SLionel Sambuc static int test_16(dep, pos, pat)
256*433d6423SLionel Sambuc dpeth_t *dep;
257*433d6423SLionel Sambuc int pos;
258*433d6423SLionel Sambuc u8_t *pat;
259*433d6423SLionel Sambuc {
260*433d6423SLionel Sambuc 	u8_t buf[4];
261*433d6423SLionel Sambuc 	int i;
262*433d6423SLionel Sambuc 	int r;
263*433d6423SLionel Sambuc 
264*433d6423SLionel Sambuc 	outb_reg0(dep, DP_ISR, 0xFF);
265*433d6423SLionel Sambuc 
266*433d6423SLionel Sambuc 	/* Setup a transfer to put the pattern. */
267*433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR0, 4);
268*433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR1, 0);
269*433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR0, pos & 0xFF);
270*433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR1, pos >> 8);
271*433d6423SLionel Sambuc 	outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
272*433d6423SLionel Sambuc 
273*433d6423SLionel Sambuc 	for (i= 0; i<4; i += 2)
274*433d6423SLionel Sambuc 	{
275*433d6423SLionel Sambuc 		outw_ne(dep, NE_DATA, *(u16_t *)(pat+i));
276*433d6423SLionel Sambuc 	}
277*433d6423SLionel Sambuc 
278*433d6423SLionel Sambuc 	for (i= 0; i<N; i++)
279*433d6423SLionel Sambuc 	{
280*433d6423SLionel Sambuc 		if (inb_reg0(dep, DP_ISR) & ISR_RDC)
281*433d6423SLionel Sambuc 			break;
282*433d6423SLionel Sambuc 	}
283*433d6423SLionel Sambuc 	if (i == N)
284*433d6423SLionel Sambuc 	{
285*433d6423SLionel Sambuc 		if (debug)
286*433d6423SLionel Sambuc 		{
287*433d6423SLionel Sambuc 			printf("%s: NE2000 remote DMA test failed\n",
288*433d6423SLionel Sambuc 				dep->de_name);
289*433d6423SLionel Sambuc 		}
290*433d6423SLionel Sambuc 		return 0;
291*433d6423SLionel Sambuc 	}
292*433d6423SLionel Sambuc 
293*433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR0, 4);
294*433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR1, 0);
295*433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR0, pos & 0xFF);
296*433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR1, pos >> 8);
297*433d6423SLionel Sambuc 	outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
298*433d6423SLionel Sambuc 
299*433d6423SLionel Sambuc 	for (i= 0; i<4; i += 2)
300*433d6423SLionel Sambuc 	{
301*433d6423SLionel Sambuc 		*(u16_t *)(buf+i)= inw_ne(dep, NE_DATA);
302*433d6423SLionel Sambuc 	}
303*433d6423SLionel Sambuc 
304*433d6423SLionel Sambuc 	r= (memcmp(buf, pat, 4) == 0);
305*433d6423SLionel Sambuc 	return r;
306*433d6423SLionel Sambuc }
307*433d6423SLionel Sambuc 
308*433d6423SLionel Sambuc /*===========================================================================*
309*433d6423SLionel Sambuc  *				ne_stop					     *
310*433d6423SLionel Sambuc  *===========================================================================*/
311*433d6423SLionel Sambuc static void ne_stop(dep)
312*433d6423SLionel Sambuc dpeth_t *dep;
313*433d6423SLionel Sambuc {
314*433d6423SLionel Sambuc 	int byte;
315*433d6423SLionel Sambuc 
316*433d6423SLionel Sambuc 	/* Reset the ethernet card */
317*433d6423SLionel Sambuc 	byte= inb_ne(dep, NE_RESET);
318*433d6423SLionel Sambuc 	milli_delay(2);
319*433d6423SLionel Sambuc 	outb_ne(dep, NE_RESET, byte);
320*433d6423SLionel Sambuc }
321*433d6423SLionel Sambuc 
322*433d6423SLionel Sambuc static void milli_delay(unsigned long millis)
323*433d6423SLionel Sambuc {
324*433d6423SLionel Sambuc 	tickdelay(MILLIS_TO_TICKS(millis));
325*433d6423SLionel Sambuc }
326*433d6423SLionel Sambuc 
327*433d6423SLionel Sambuc #endif /* ENABLE_NE2000 */
328*433d6423SLionel Sambuc 
329*433d6423SLionel Sambuc /*
330*433d6423SLionel Sambuc  * $PchId: ne2000.c,v 1.10 2004/08/03 12:03:00 philip Exp $
331*433d6423SLionel Sambuc  */
332