xref: /minix3/minix/drivers/net/dp8390/ne2000.c (revision d4dd6511b9dc029206ce2c925ed135e16555aae4)
1433d6423SLionel Sambuc /*
2433d6423SLionel Sambuc ne2000.c
3433d6423SLionel Sambuc 
4433d6423SLionel Sambuc Driver for the ne2000 ethernet cards. This file contains only the ne2000
5433d6423SLionel Sambuc specific code, the rest is in dp8390.c
6433d6423SLionel Sambuc 
7433d6423SLionel Sambuc Created:	March 15, 1994 by Philip Homburg <philip@f-mnx.phicoh.com>
8433d6423SLionel Sambuc */
9433d6423SLionel Sambuc 
10433d6423SLionel Sambuc #include <minix/drivers.h>
113913e490SDavid van Moolenbroek #include <minix/netdriver.h>
12433d6423SLionel Sambuc 
13433d6423SLionel Sambuc #include "local.h"
14433d6423SLionel Sambuc #include "dp8390.h"
15433d6423SLionel Sambuc #include "ne2000.h"
16433d6423SLionel Sambuc 
17433d6423SLionel Sambuc #if ENABLE_NE2000
18433d6423SLionel Sambuc 
19433d6423SLionel Sambuc #define N 100
20433d6423SLionel Sambuc 
21433d6423SLionel Sambuc extern u32_t system_hz;
22433d6423SLionel Sambuc 
23433d6423SLionel Sambuc #define MILLIS_TO_TICKS(m)  (((m)*system_hz/1000)+1)
24433d6423SLionel Sambuc 
25433d6423SLionel Sambuc typedef int(*testf_t) (dpeth_t *dep, int pos, u8_t *pat);
26433d6423SLionel Sambuc 
27433d6423SLionel Sambuc static u8_t	pat0[]= { 0x00, 0x00, 0x00, 0x00 };
28433d6423SLionel Sambuc static u8_t	pat1[]= { 0xFF, 0xFF, 0xFF, 0xFF };
29433d6423SLionel Sambuc static u8_t	pat2[]= { 0xA5, 0x5A, 0x69, 0x96 };
30433d6423SLionel Sambuc static u8_t	pat3[]= { 0x96, 0x69, 0x5A, 0xA5 };
31433d6423SLionel Sambuc 
32433d6423SLionel Sambuc static int test_8(dpeth_t *dep, int pos, u8_t *pat);
33433d6423SLionel Sambuc static int test_16(dpeth_t *dep, int pos, u8_t *pat);
34433d6423SLionel Sambuc static void ne_stop(dpeth_t *dep);
35433d6423SLionel Sambuc 
36433d6423SLionel Sambuc /*===========================================================================*
37433d6423SLionel Sambuc  *				ne_probe				     *
38433d6423SLionel Sambuc  *===========================================================================*/
ne_probe(dpeth_t * dep)39433d6423SLionel Sambuc int ne_probe(dpeth_t *dep)
40433d6423SLionel Sambuc {
41433d6423SLionel Sambuc 	int byte;
42433d6423SLionel Sambuc 	int i;
43433d6423SLionel Sambuc 	int loc1, loc2;
44433d6423SLionel Sambuc 	testf_t f;
45433d6423SLionel Sambuc 
46433d6423SLionel Sambuc 	dep->de_dp8390_port= dep->de_base_port + NE_DP8390;
47433d6423SLionel Sambuc 
48433d6423SLionel Sambuc 	/* We probe for an ne1000 or an ne2000 by testing whether the
49433d6423SLionel Sambuc 	 * on board is reachable through the dp8390. Note that the
50433d6423SLionel Sambuc 	 * ne1000 is an 8bit card and has a memory region distict from
51433d6423SLionel Sambuc 	 * the 16bit ne2000
52433d6423SLionel Sambuc 	 */
53433d6423SLionel Sambuc 
54433d6423SLionel Sambuc 	for (dep->de_16bit= 0; dep->de_16bit < 2; dep->de_16bit++)
55433d6423SLionel Sambuc 	{
56433d6423SLionel Sambuc 		/* Reset the ethernet card */
57433d6423SLionel Sambuc 		byte= inb_ne(dep, NE_RESET);
58*d4dd6511Srlfnb 		micro_delay(2000);
59433d6423SLionel Sambuc 		outb_ne(dep, NE_RESET, byte);
60*d4dd6511Srlfnb 		micro_delay(2000);
61433d6423SLionel Sambuc 
62433d6423SLionel Sambuc 		/* Reset the dp8390 */
63433d6423SLionel Sambuc 		outb_reg0(dep, DP_CR, CR_STP | CR_DM_ABORT);
64433d6423SLionel Sambuc 		for (i= 0; i < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RST) == 0); i++)
65433d6423SLionel Sambuc 			; /* Do nothing */
66433d6423SLionel Sambuc 
67433d6423SLionel Sambuc 		/* Check if the dp8390 is really there */
68433d6423SLionel Sambuc 		if ((inb_reg0(dep, DP_CR) & (CR_STP|CR_DM_ABORT)) !=
69433d6423SLionel Sambuc 			(CR_STP|CR_DM_ABORT))
70433d6423SLionel Sambuc 		{
71433d6423SLionel Sambuc 			return 0;
72433d6423SLionel Sambuc 		}
73433d6423SLionel Sambuc 
74433d6423SLionel Sambuc 		/* Disable the receiver and init TCR and DCR. */
75433d6423SLionel Sambuc 		outb_reg0(dep, DP_RCR, RCR_MON);
76433d6423SLionel Sambuc 		outb_reg0(dep, DP_TCR, TCR_NORMAL);
77433d6423SLionel Sambuc 		if (dep->de_16bit)
78433d6423SLionel Sambuc 		{
79433d6423SLionel Sambuc 			outb_reg0(dep, DP_DCR, DCR_WORDWIDE | DCR_8BYTES |
80433d6423SLionel Sambuc 				DCR_BMS);
81433d6423SLionel Sambuc 		}
82433d6423SLionel Sambuc 		else
83433d6423SLionel Sambuc 		{
84433d6423SLionel Sambuc 			outb_reg0(dep, DP_DCR, DCR_BYTEWIDE | DCR_8BYTES |
85433d6423SLionel Sambuc 				DCR_BMS);
86433d6423SLionel Sambuc 		}
87433d6423SLionel Sambuc 
88433d6423SLionel Sambuc 		if (dep->de_16bit)
89433d6423SLionel Sambuc 		{
90433d6423SLionel Sambuc 			loc1= NE2000_START;
91433d6423SLionel Sambuc 			loc2= NE2000_START + NE2000_SIZE - 4;
92433d6423SLionel Sambuc 			f= test_16;
93433d6423SLionel Sambuc 		}
94433d6423SLionel Sambuc 		else
95433d6423SLionel Sambuc 		{
96433d6423SLionel Sambuc 			loc1= NE1000_START;
97433d6423SLionel Sambuc 			loc2= NE1000_START + NE1000_SIZE - 4;
98433d6423SLionel Sambuc 			f= test_8;
99433d6423SLionel Sambuc 		}
100433d6423SLionel Sambuc 		if (f(dep, loc1, pat0) && f(dep, loc1, pat1) &&
101433d6423SLionel Sambuc 			f(dep, loc1, pat2) && f(dep, loc1, pat3) &&
102433d6423SLionel Sambuc 			f(dep, loc2, pat0) && f(dep, loc2, pat1) &&
103433d6423SLionel Sambuc 			f(dep, loc2, pat2) && f(dep, loc2, pat3))
104433d6423SLionel Sambuc 		{
105433d6423SLionel Sambuc 			/* We don't need a memory segment */
106433d6423SLionel Sambuc 			dep->de_linmem= 0;
107433d6423SLionel Sambuc 			if (!dep->de_pci)
108433d6423SLionel Sambuc 				dep->de_initf= ne_init;
109433d6423SLionel Sambuc 			dep->de_stopf= ne_stop;
110433d6423SLionel Sambuc 			dep->de_prog_IO= 1;
111433d6423SLionel Sambuc 			return 1;
112433d6423SLionel Sambuc 		}
113433d6423SLionel Sambuc 	}
114433d6423SLionel Sambuc 	return 0;
115433d6423SLionel Sambuc }
116433d6423SLionel Sambuc 
117433d6423SLionel Sambuc /*===========================================================================*
118433d6423SLionel Sambuc  *				ne_init					     *
119433d6423SLionel Sambuc  *===========================================================================*/
ne_init(dep)120433d6423SLionel Sambuc void ne_init(dep)
121433d6423SLionel Sambuc dpeth_t *dep;
122433d6423SLionel Sambuc {
123433d6423SLionel Sambuc 	int i;
124433d6423SLionel Sambuc 	int word, sendq_nr;
125433d6423SLionel Sambuc 
126433d6423SLionel Sambuc 	/* Setup a transfer to get the ethernet address. */
127433d6423SLionel Sambuc 	if (dep->de_16bit)
128433d6423SLionel Sambuc 		outb_reg0(dep, DP_RBCR0, 6*2);
129433d6423SLionel Sambuc 	else
130433d6423SLionel Sambuc 		outb_reg0(dep, DP_RBCR0, 6);
131433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR1, 0);
132433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR0, 0);
133433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR1, 0);
134433d6423SLionel Sambuc 	outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
135433d6423SLionel Sambuc 
136433d6423SLionel Sambuc 	for (i= 0; i<6; i++)
137433d6423SLionel Sambuc 	{
138433d6423SLionel Sambuc 		if (dep->de_16bit)
139433d6423SLionel Sambuc 		{
140433d6423SLionel Sambuc 			word= inw_ne(dep, NE_DATA);
141f7df02e7SDavid van Moolenbroek 			dep->de_address.na_addr[i]= word;
142433d6423SLionel Sambuc 		}
143433d6423SLionel Sambuc 		else
144433d6423SLionel Sambuc 		{
145f7df02e7SDavid van Moolenbroek 			dep->de_address.na_addr[i] = inb_ne(dep, NE_DATA);
146433d6423SLionel Sambuc 		}
147433d6423SLionel Sambuc 	}
148433d6423SLionel Sambuc 	dep->de_data_port= dep->de_base_port + NE_DATA;
149433d6423SLionel Sambuc 	if (dep->de_16bit)
150433d6423SLionel Sambuc 	{
151433d6423SLionel Sambuc 		dep->de_ramsize= NE2000_SIZE;
152433d6423SLionel Sambuc 		dep->de_offset_page= NE2000_START / DP_PAGESIZE;
153433d6423SLionel Sambuc 	}
154433d6423SLionel Sambuc 	else
155433d6423SLionel Sambuc 	{
156433d6423SLionel Sambuc 		dep->de_ramsize= NE1000_SIZE;
157433d6423SLionel Sambuc 		dep->de_offset_page= NE1000_START / DP_PAGESIZE;
158433d6423SLionel Sambuc 	}
159433d6423SLionel Sambuc 
160433d6423SLionel Sambuc 	/* Allocate one send buffer (1.5KB) per 8KB of on board memory. */
161433d6423SLionel Sambuc 	sendq_nr= dep->de_ramsize / 0x2000;
162433d6423SLionel Sambuc 	if (sendq_nr < 1)
163433d6423SLionel Sambuc 		sendq_nr= 1;
164433d6423SLionel Sambuc 	else if (sendq_nr > SENDQ_NR)
165433d6423SLionel Sambuc 		sendq_nr= SENDQ_NR;
166433d6423SLionel Sambuc 	dep->de_sendq_nr= sendq_nr;
167433d6423SLionel Sambuc 	for (i= 0; i<sendq_nr; i++)
168433d6423SLionel Sambuc 	{
169433d6423SLionel Sambuc 		dep->de_sendq[i].sq_sendpage= dep->de_offset_page +
170433d6423SLionel Sambuc 			i*SENDQ_PAGES;
171433d6423SLionel Sambuc 	}
172433d6423SLionel Sambuc 
173433d6423SLionel Sambuc 	dep->de_startpage= dep->de_offset_page + i*SENDQ_PAGES;
174433d6423SLionel Sambuc 	dep->de_stoppage= dep->de_offset_page + dep->de_ramsize / DP_PAGESIZE;
175433d6423SLionel Sambuc 
176433d6423SLionel Sambuc 	/* Can't override the default IRQ. */
177433d6423SLionel Sambuc 	dep->de_irq &= ~DEI_DEFAULT;
178433d6423SLionel Sambuc 
179433d6423SLionel Sambuc 	if (!debug)
180433d6423SLionel Sambuc 	{
181433d6423SLionel Sambuc 		printf("%s: NE%d000 at %X:%d\n",
182f7df02e7SDavid van Moolenbroek 			netdriver_name(), dep->de_16bit ? 2 : 1,
183433d6423SLionel Sambuc 			dep->de_base_port, dep->de_irq);
184433d6423SLionel Sambuc 	}
185433d6423SLionel Sambuc 	else
186433d6423SLionel Sambuc 	{
187433d6423SLionel Sambuc 		printf("%s: Novell NE%d000 ethernet card at I/O address "
188433d6423SLionel Sambuc 			"0x%X, memory size 0x%X, irq %d\n",
189f7df02e7SDavid van Moolenbroek 			netdriver_name(), dep->de_16bit ? 2 : 1,
190433d6423SLionel Sambuc 			dep->de_base_port, dep->de_ramsize, dep->de_irq);
191433d6423SLionel Sambuc 	}
192433d6423SLionel Sambuc }
193433d6423SLionel Sambuc 
194433d6423SLionel Sambuc /*===========================================================================*
195433d6423SLionel Sambuc  *				test_8					     *
196433d6423SLionel Sambuc  *===========================================================================*/
test_8(dep,pos,pat)197433d6423SLionel Sambuc static int test_8(dep, pos, pat)
198433d6423SLionel Sambuc dpeth_t *dep;
199433d6423SLionel Sambuc int pos;
200433d6423SLionel Sambuc u8_t *pat;
201433d6423SLionel Sambuc {
202433d6423SLionel Sambuc 	u8_t buf[4];
203433d6423SLionel Sambuc 	int i;
204433d6423SLionel Sambuc 	int r;
205433d6423SLionel Sambuc 
206433d6423SLionel Sambuc 	outb_reg0(dep, DP_ISR, 0xFF);
207433d6423SLionel Sambuc 
208433d6423SLionel Sambuc 	/* Setup a transfer to put the pattern. */
209433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR0, 4);
210433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR1, 0);
211433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR0, pos & 0xFF);
212433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR1, pos >> 8);
213433d6423SLionel Sambuc 	outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
214433d6423SLionel Sambuc 
215433d6423SLionel Sambuc 	for (i= 0; i<4; i++)
216433d6423SLionel Sambuc 		outb_ne(dep, NE_DATA, pat[i]);
217433d6423SLionel Sambuc 
218433d6423SLionel Sambuc 	for (i= 0; i<N; i++)
219433d6423SLionel Sambuc 	{
220433d6423SLionel Sambuc 		if (inb_reg0(dep, DP_ISR) & ISR_RDC)
221433d6423SLionel Sambuc 			break;
222433d6423SLionel Sambuc 	}
223433d6423SLionel Sambuc 	if (i == N)
224433d6423SLionel Sambuc 	{
225433d6423SLionel Sambuc 		if (debug)
226433d6423SLionel Sambuc 		{
227433d6423SLionel Sambuc 			printf("%s: NE1000 remote DMA test failed\n",
228f7df02e7SDavid van Moolenbroek 				netdriver_name());
229433d6423SLionel Sambuc 		}
230433d6423SLionel Sambuc 		return 0;
231433d6423SLionel Sambuc 	}
232433d6423SLionel Sambuc 
233433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR0, 4);
234433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR1, 0);
235433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR0, pos & 0xFF);
236433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR1, pos >> 8);
237433d6423SLionel Sambuc 	outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
238433d6423SLionel Sambuc 
239433d6423SLionel Sambuc 	for (i= 0; i<4; i++)
240433d6423SLionel Sambuc 		buf[i]= inb_ne(dep, NE_DATA);
241433d6423SLionel Sambuc 
242433d6423SLionel Sambuc 	r= (memcmp(buf, pat, 4) == 0);
243433d6423SLionel Sambuc 	return r;
244433d6423SLionel Sambuc }
245433d6423SLionel Sambuc 
246433d6423SLionel Sambuc /*===========================================================================*
247433d6423SLionel Sambuc  *				test_16					     *
248433d6423SLionel Sambuc  *===========================================================================*/
test_16(dep,pos,pat)249433d6423SLionel Sambuc static int test_16(dep, pos, pat)
250433d6423SLionel Sambuc dpeth_t *dep;
251433d6423SLionel Sambuc int pos;
252433d6423SLionel Sambuc u8_t *pat;
253433d6423SLionel Sambuc {
254433d6423SLionel Sambuc 	u8_t buf[4];
255433d6423SLionel Sambuc 	int i;
256433d6423SLionel Sambuc 	int r;
257433d6423SLionel Sambuc 
258433d6423SLionel Sambuc 	outb_reg0(dep, DP_ISR, 0xFF);
259433d6423SLionel Sambuc 
260433d6423SLionel Sambuc 	/* Setup a transfer to put the pattern. */
261433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR0, 4);
262433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR1, 0);
263433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR0, pos & 0xFF);
264433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR1, pos >> 8);
265433d6423SLionel Sambuc 	outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
266433d6423SLionel Sambuc 
267433d6423SLionel Sambuc 	for (i= 0; i<4; i += 2)
268433d6423SLionel Sambuc 	{
269433d6423SLionel Sambuc 		outw_ne(dep, NE_DATA, *(u16_t *)(pat+i));
270433d6423SLionel Sambuc 	}
271433d6423SLionel Sambuc 
272433d6423SLionel Sambuc 	for (i= 0; i<N; i++)
273433d6423SLionel Sambuc 	{
274433d6423SLionel Sambuc 		if (inb_reg0(dep, DP_ISR) & ISR_RDC)
275433d6423SLionel Sambuc 			break;
276433d6423SLionel Sambuc 	}
277433d6423SLionel Sambuc 	if (i == N)
278433d6423SLionel Sambuc 	{
279433d6423SLionel Sambuc 		if (debug)
280433d6423SLionel Sambuc 		{
281433d6423SLionel Sambuc 			printf("%s: NE2000 remote DMA test failed\n",
282f7df02e7SDavid van Moolenbroek 				netdriver_name());
283433d6423SLionel Sambuc 		}
284433d6423SLionel Sambuc 		return 0;
285433d6423SLionel Sambuc 	}
286433d6423SLionel Sambuc 
287433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR0, 4);
288433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR1, 0);
289433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR0, pos & 0xFF);
290433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR1, pos >> 8);
291433d6423SLionel Sambuc 	outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
292433d6423SLionel Sambuc 
293433d6423SLionel Sambuc 	for (i= 0; i<4; i += 2)
294433d6423SLionel Sambuc 	{
295433d6423SLionel Sambuc 		*(u16_t *)(buf+i)= inw_ne(dep, NE_DATA);
296433d6423SLionel Sambuc 	}
297433d6423SLionel Sambuc 
298433d6423SLionel Sambuc 	r= (memcmp(buf, pat, 4) == 0);
299433d6423SLionel Sambuc 	return r;
300433d6423SLionel Sambuc }
301433d6423SLionel Sambuc 
302433d6423SLionel Sambuc /*===========================================================================*
303433d6423SLionel Sambuc  *				ne_stop					     *
304433d6423SLionel Sambuc  *===========================================================================*/
ne_stop(dep)305433d6423SLionel Sambuc static void ne_stop(dep)
306433d6423SLionel Sambuc dpeth_t *dep;
307433d6423SLionel Sambuc {
308433d6423SLionel Sambuc 	int byte;
309433d6423SLionel Sambuc 
310433d6423SLionel Sambuc 	/* Reset the ethernet card */
311433d6423SLionel Sambuc 	byte= inb_ne(dep, NE_RESET);
312*d4dd6511Srlfnb 	micro_delay(2000);
313433d6423SLionel Sambuc 	outb_ne(dep, NE_RESET, byte);
314433d6423SLionel Sambuc }
315433d6423SLionel Sambuc 
316433d6423SLionel Sambuc #endif /* ENABLE_NE2000 */
317433d6423SLionel Sambuc 
318433d6423SLionel Sambuc /*
319433d6423SLionel Sambuc  * $PchId: ne2000.c,v 1.10 2004/08/03 12:03:00 philip Exp $
320433d6423SLionel Sambuc  */
321