xref: /openbsd-src/sys/dev/isa/if_le_isa.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenBSD: if_le_isa.c,v 1.14 1998/09/16 22:41:21 jason Exp $	*/
2 /*	$NetBSD: if_le_isa.c,v 1.2 1996/05/12 23:52:56 mycroft Exp $	*/
3 
4 /*-
5  * Copyright (c) 1995 Charles M. Hannum.  All rights reserved.
6  * Copyright (c) 1992, 1993
7  *	The Regents of the University of California.  All rights reserved.
8  *
9  * This code is derived from software contributed to Berkeley by
10  * Ralph Campbell and Rick Macklem.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  *	This product includes software developed by the University of
23  *	California, Berkeley and its contributors.
24  * 4. Neither the name of the University nor the names of its contributors
25  *    may be used to endorse or promote products derived from this software
26  *    without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  *
40  *	@(#)if_le.c	8.2 (Berkeley) 11/16/93
41  */
42 
43 #include "bpfilter.h"
44 #include "isadma.h"
45 
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/mbuf.h>
49 #include <sys/syslog.h>
50 #include <sys/socket.h>
51 #include <sys/device.h>
52 
53 #include <net/if.h>
54 #include <net/if_media.h>
55 
56 #ifdef INET
57 #include <netinet/in.h>
58 #include <netinet/if_ether.h>
59 #endif
60 
61 #include <vm/vm.h>
62 
63 #include <machine/cpu.h>
64 #include <machine/intr.h>
65 
66 #include <dev/isa/isareg.h>
67 #include <dev/isa/isavar.h>
68 #include <dev/isa/isadmavar.h>
69 
70 #include <dev/ic/am7990reg.h>
71 #include <dev/ic/am7990var.h>
72 
73 #include <dev/isa/if_levar.h>
74 
75 static char *card_type[] =
76     { "unknown", "BICC Isolan", "NE2100", "DEPCA", "PCnet-ISA" };
77 
78 int le_isa_probe __P((struct device *, void *, void *));
79 void le_isa_attach __P((struct device *, struct device *, void *));
80 
81 struct cfattach le_isa_ca = {
82 	sizeof(struct le_softc), le_isa_probe, le_isa_attach
83 };
84 
85 int depca_isa_probe __P((struct le_softc *, struct isa_attach_args *));
86 int ne2100_isa_probe __P((struct le_softc *, struct isa_attach_args *));
87 int bicc_isa_probe __P((struct le_softc *, struct isa_attach_args *));
88 int lance_isa_probe __P((struct am7990_softc *));
89 
90 int
91 le_isa_probe(parent, match, aux)
92 	struct device *parent;
93 	void *match, *aux;
94 {
95 	struct le_softc *lesc = match;
96 	struct isa_attach_args *ia = aux;
97 	u_int8_t bogusether[ETHER_ADDR_LEN] = { 255, 255, 255, 255, 255, 255 };
98 
99 #if NISADMA == 0
100 	if (ia->ia_drq != DRQUNK) {
101 		printf("cannot support dma lance devices\n");
102 		return 0;
103 	}
104 #endif
105 
106 	if (bicc_isa_probe(lesc, ia) == 0 && ne2100_isa_probe(lesc, ia) == 0 &&
107 	    depca_isa_probe(lesc, ia) == 0)
108 		return (0);
109 
110 	if (bcmp(lesc->sc_am7990.sc_arpcom.ac_enaddr, bogusether,
111 	    sizeof(bogusether)) == 0)
112 		return (0);
113 
114 	return (1);
115 }
116 
117 int
118 depca_isa_probe(lesc, ia)
119 	struct le_softc *lesc;
120 	struct isa_attach_args *ia;
121 {
122 	struct am7990_softc *sc = &lesc->sc_am7990;
123 	bus_space_tag_t iot = lesc->sc_iot;
124 	bus_space_handle_t ioh = lesc->sc_ioh;
125 	int iosize = 16;
126 	int port;
127 
128 #if 0
129 	u_long sum, rom_sum;
130 	u_char x;
131 #endif
132 	int i;
133 
134 	if (bus_space_map(iot, ia->ia_iobase, iosize, 0, &ioh))
135 		return (0);
136 	lesc->sc_iot = iot;
137 	lesc->sc_ioh = ioh;
138 	lesc->sc_rap = DEPCA_RAP;
139 	lesc->sc_rdp = DEPCA_RDP;
140 	lesc->sc_card = DEPCA;
141 
142 	if (lance_isa_probe(sc) == 0) {
143 		bus_space_unmap(iot, ioh, iosize);
144 		return 0;
145 	}
146 
147 	bus_space_write_1(iot, ioh, DEPCA_CSR, DEPCA_CSR_DUM);
148 
149 	/*
150 	 * Extract the physical MAC address from the ROM.
151 	 *
152 	 * The address PROM is 32 bytes wide, and we access it through
153 	 * a single I/O port.  On each read, it rotates to the next
154 	 * position.  We find the ethernet address by looking for a
155 	 * particular sequence of bytes (0xff, 0x00, 0x55, 0xaa, 0xff,
156 	 * 0x00, 0x55, 0xaa), and then reading the next 8 bytes (the
157 	 * ethernet address and a checksum).
158 	 *
159 	 * It appears that the PROM can be at one of two locations, so
160 	 * we just try both.
161 	 */
162 	port = DEPCA_ADP;
163 	for (i = 0; i < 32; i++)
164 		if (bus_space_read_1(iot, ioh, port) == 0xff &&
165 		    bus_space_read_1(iot, ioh, port) == 0x00 &&
166 		    bus_space_read_1(iot, ioh, port) == 0x55 &&
167 		    bus_space_read_1(iot, ioh, port) == 0xaa &&
168 		    bus_space_read_1(iot, ioh, port) == 0xff &&
169 		    bus_space_read_1(iot, ioh, port) == 0x00 &&
170 		    bus_space_read_1(iot, ioh, port) == 0x55 &&
171 		    bus_space_read_1(iot, ioh, port) == 0xaa)
172 			goto found;
173 	port = DEPCA_ADP + 1;
174 	for (i = 0; i < 32; i++)
175 		if (bus_space_read_1(iot, ioh, port) == 0xff &&
176 		    bus_space_read_1(iot, ioh, port) == 0x00 &&
177 		    bus_space_read_1(iot, ioh, port) == 0x55 &&
178 		    bus_space_read_1(iot, ioh, port) == 0xaa &&
179 		    bus_space_read_1(iot, ioh, port) == 0xff &&
180 		    bus_space_read_1(iot, ioh, port) == 0x00 &&
181 		    bus_space_read_1(iot, ioh, port) == 0x55 &&
182 		    bus_space_read_1(iot, ioh, port) == 0xaa)
183 			goto found;
184 	printf("%s: address not found\n", sc->sc_dev.dv_xname);
185 	return 0;
186 
187 found:
188 	for (i = 0; i < sizeof(sc->sc_arpcom.ac_enaddr); i++)
189 		sc->sc_arpcom.ac_enaddr[i] = bus_space_read_1(iot, ioh, port);
190 
191 #if 0
192 	sum =
193 	    (sc->sc_arpcom.ac_enaddr[0] <<  2) +
194 	    (sc->sc_arpcom.ac_enaddr[1] << 10) +
195 	    (sc->sc_arpcom.ac_enaddr[2] <<  1) +
196 	    (sc->sc_arpcom.ac_enaddr[3] <<  9) +
197 	    (sc->sc_arpcom.ac_enaddr[4] <<  0) +
198 	    (sc->sc_arpcom.ac_enaddr[5] <<  8);
199 	sum = (sum & 0xffff) + (sum >> 16);
200 	sum = (sum & 0xffff) + (sum >> 16);
201 
202 	rom_sum = bus_space_read_1(iot, ioh, port);
203 	rom_sum |= bus_space_read_1(iot, ioh, port << 8);
204 
205 	if (sum != rom_sum) {
206 		printf("%s: checksum mismatch; calculated %04x != read %04x",
207 		    sc->sc_dev.dv_xname, sum, rom_sum);
208 		bus_space_unmap(iot, ioh, iosize);
209 		return 0;
210 	}
211 #endif
212 
213 	bus_space_write_1(iot, ioh, DEPCA_CSR, DEPCA_CSR_NORMAL);
214 
215 	ia->ia_iosize = iosize;
216 	ia->ia_drq = DRQUNK;
217 	bus_space_unmap(iot, ioh, ia->ia_iosize);
218 	return 1;
219 }
220 
221 int
222 ne2100_isa_probe(lesc, ia)
223 	struct le_softc *lesc;
224 	struct isa_attach_args *ia;
225 {
226 	struct am7990_softc *sc = &lesc->sc_am7990;
227 	bus_space_tag_t iot = lesc->sc_iot;
228 	bus_space_handle_t ioh = lesc->sc_ioh;
229 	int iosize = 24;
230 	int i;
231 
232 	if (bus_space_map(iot, ia->ia_iobase, iosize, 0, &ioh))
233 		return (0);
234 	lesc->sc_iot = iot;
235 	lesc->sc_ioh = ioh;
236 	lesc->sc_rap = NE2100_RAP;
237 	lesc->sc_rdp = NE2100_RDP;
238 	lesc->sc_card = NE2100;
239 
240 	if (lance_isa_probe(sc) == 0) {
241 		bus_space_unmap(iot, ioh, iosize);
242 		return 0;
243 	}
244 
245 	/*
246 	 * Extract the physical MAC address from the ROM.
247 	 */
248 	for (i = 0; i < sizeof(sc->sc_arpcom.ac_enaddr); i++)
249 		sc->sc_arpcom.ac_enaddr[i] = bus_space_read_1(iot, ioh, i);
250 
251 	ia->ia_iosize = iosize;
252 	bus_space_unmap(iot, ioh, ia->ia_iosize);
253 	return 1;
254 }
255 
256 int
257 bicc_isa_probe(lesc, ia)
258 	struct le_softc *lesc;
259 	struct isa_attach_args *ia;
260 {
261 	struct am7990_softc *sc = &lesc->sc_am7990;
262 	bus_space_handle_t ioh;
263 	bus_space_tag_t iot = ia->ia_iot;
264 	int iosize = 16;
265 	int i;
266 
267 	if (bus_space_map(iot, ia->ia_iobase, iosize, 0, &ioh))
268 		return (0);
269 	lesc->sc_iot = iot;
270 	lesc->sc_ioh = ioh;
271 	lesc->sc_rap = BICC_RAP;
272 	lesc->sc_rdp = BICC_RDP;
273 	lesc->sc_card = BICC;
274 
275 	if (lance_isa_probe(sc) == 0) {
276 		bus_space_unmap(iot, ioh, iosize);
277 		return 0;
278 	}
279 
280 	/*
281 	 * Extract the physical MAC address from the ROM.
282 	 */
283 	for (i = 0; i < sizeof(sc->sc_arpcom.ac_enaddr); i++)
284 		sc->sc_arpcom.ac_enaddr[i] = bus_space_read_1(iot, ioh, i * 2);
285 
286 	ia->ia_iosize = iosize;
287 	bus_space_unmap(iot, ioh, ia->ia_iosize);
288 	return 1;
289 }
290 
291 /*
292  * Determine which chip is present on the card.
293  */
294 int
295 lance_isa_probe(sc)
296 	struct am7990_softc *sc;
297 {
298 
299 	/* Stop the LANCE chip and put it in a known state. */
300 	le_isa_wrcsr(sc, LE_CSR0, LE_C0_STOP);
301 	delay(100);
302 
303 	if (le_isa_rdcsr(sc, LE_CSR0) != LE_C0_STOP)
304 		return 0;
305 
306 	le_isa_wrcsr(sc, LE_CSR3, sc->sc_conf3);
307 	return 1;
308 }
309 
310 void
311 le_isa_attach(parent, self, aux)
312 	struct device *parent, *self;
313 	void *aux;
314 {
315 	struct le_softc *lesc = (void *)self;
316 	struct am7990_softc *sc = &lesc->sc_am7990;
317 	struct isa_attach_args *ia = aux;
318 	bus_space_tag_t iot = ia->ia_iot;
319 	bus_space_handle_t ioh;
320 
321 	if (bus_space_map(iot, ia->ia_iobase, ia->ia_iosize, 0, &ioh))
322 		panic("%s: could not map I/O-ports", sc->sc_dev.dv_xname);
323 	lesc->sc_iot = iot;
324 	lesc->sc_ioh = ioh;
325 
326 	printf(": %s Ethernet\n", card_type[lesc->sc_card]);
327 
328 	if (lesc->sc_card == DEPCA) {
329 		u_char *mem, val;
330 		int i;
331 
332 		mem = sc->sc_mem = ISA_HOLE_VADDR(ia->ia_maddr);
333 
334 		val = 0xff;
335 		for (;;) {
336 			for (i = 0; i < ia->ia_msize; i++)
337 				mem[i] = val;
338 			for (i = 0; i < ia->ia_msize; i++)
339 				if (mem[i] != val) {
340 					printf("%s: failed to clear memory\n",
341 					    sc->sc_dev.dv_xname);
342 					return;
343 				}
344 			if (val == 0x00)
345 				break;
346 			val -= 0x55;
347 		}
348 
349 		sc->sc_conf3 = LE_C3_ACON;
350 		sc->sc_addr = 0;
351 		sc->sc_memsize = ia->ia_msize;
352 	} else {
353 		sc->sc_mem = malloc(16384, M_DEVBUF, M_NOWAIT);
354 		if (sc->sc_mem == 0) {
355 			printf("%s: couldn't allocate memory for card\n",
356 			    sc->sc_dev.dv_xname);
357 			return;
358 		}
359 
360 		sc->sc_conf3 = 0;
361 		sc->sc_addr = kvtop(sc->sc_mem);
362 		sc->sc_memsize = 16384;
363 	}
364 
365 	sc->sc_copytodesc = am7990_copytobuf_contig;
366 	sc->sc_copyfromdesc = am7990_copyfrombuf_contig;
367 	sc->sc_copytobuf = am7990_copytobuf_contig;
368 	sc->sc_copyfrombuf = am7990_copyfrombuf_contig;
369 	sc->sc_zerobuf = am7990_zerobuf_contig;
370 
371 	sc->sc_rdcsr = le_isa_rdcsr;
372 	sc->sc_wrcsr = le_isa_wrcsr;
373 	sc->sc_hwreset = NULL;
374 	sc->sc_hwinit = NULL;
375 
376 	printf("%s", sc->sc_dev.dv_xname);
377 	am7990_config(sc);
378 
379 #if NISADMA > 0
380 	if (ia->ia_drq != DRQUNK)
381 		isadma_cascade(ia->ia_drq);
382 #endif
383 
384 	lesc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
385 	    IPL_NET, le_isa_intredge, sc, sc->sc_dev.dv_xname);
386 }
387