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