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