xref: /openbsd-src/sys/dev/isa/if_we.c (revision 26c802275ce923e950bd0e243fa8e3d01df4ee4c)
1 /*	$OpenBSD: if_we.c,v 1.5 1998/12/23 00:33:29 aaron Exp $	*/
2 /*	$NetBSD: if_we.c,v 1.11 1998/07/05 06:49:14 jonathan Exp $	*/
3 
4 /*-
5  * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10  * NASA Ames Research Center.
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 NetBSD
23  *	Foundation, Inc. and its contributors.
24  * 4. Neither the name of The NetBSD Foundation nor the names of its
25  *    contributors may be used to endorse or promote products derived
26  *    from this software without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38  * POSSIBILITY OF SUCH DAMAGE.
39  */
40 
41 /*
42  * Device driver for National Semiconductor DS8390/WD83C690 based ethernet
43  * adapters.
44  *
45  * Copyright (c) 1994, 1995 Charles M. Hannum.  All rights reserved.
46  *
47  * Copyright (C) 1993, David Greenman.  This software may be used, modified,
48  * copied, distributed, and sold, in both source and binary form provided that
49  * the above copyright and these terms are retained.  Under no circumstances is
50  * the author responsible for the proper functioning of this software, nor does
51  * the author assume any responsibility for damages incurred with its use.
52  */
53 
54 /*
55  * Device driver for the Western Digital/SMC 8003 and 8013 series,
56  * and the SMC Elite Ultra (8216).
57  */
58 
59 #include "bpfilter.h"
60 #include "we.h"
61 
62 #include <sys/param.h>
63 #include <sys/systm.h>
64 #include <sys/device.h>
65 #include <sys/socket.h>
66 #include <sys/mbuf.h>
67 #include <sys/syslog.h>
68 
69 #include <net/if.h>
70 #include <net/if_dl.h>
71 #include <net/if_types.h>
72 #include <net/if_media.h>
73 
74 #ifdef __NetBSD__
75 #include <net/if_ether.h>
76 #endif
77 
78 #ifdef INET
79 #include <netinet/in.h>
80 #include <netinet/in_systm.h>
81 #include <netinet/in_var.h>
82 #include <netinet/ip.h>
83 #ifdef __NetBSD__
84 #include <netinet/if_inarp.h>
85 #else
86 #include <netinet/if_ether.h>
87 #endif
88 #endif
89 
90 #ifdef NS
91 #include <netns/ns.h>
92 #include <netns/ns_if.h>
93 #endif
94 
95 #if NBPFILTER > 0
96 #include <net/bpf.h>
97 #include <net/bpfdesc.h>
98 #endif
99 
100 #include <machine/bus.h>
101 #include <machine/intr.h>
102 
103 #include <dev/isa/isareg.h>
104 #include <dev/isa/isavar.h>
105 
106 #include <dev/ic/dp8390reg.h>
107 #include <dev/ic/dp8390var.h>
108 
109 #include <dev/isa/if_wereg.h>
110 
111 #ifndef __BUS_SPACE_HAS_STREAM_METHODS
112 #define	bus_space_read_region_stream_2	bus_space_read_region_2
113 #define	bus_space_write_stream_2	bus_space_write_2
114 #define	bus_space_write_region_stream_2	bus_space_write_region_2
115 #endif
116 
117 struct we_softc {
118 	struct dp8390_softc sc_dp8390;
119 
120 	bus_space_tag_t sc_asict;	/* space tag for ASIC */
121 	bus_space_handle_t sc_asich;	/* space handle for ASIC */
122 
123 	u_int8_t sc_laar_proto;
124 	u_int8_t sc_msr_proto;
125 
126 	u_int8_t sc_type;		/* our type */
127 
128 	int sc_16bitp;			/* are we 16 bit? */
129 
130 	void *sc_ih;			/* interrupt handle */
131 };
132 
133 int	we_probe __P((struct device *, void *, void *));
134 void	we_attach __P((struct device *, struct device *, void *));
135 
136 struct cfattach we_isa_ca = {
137 	sizeof(struct we_softc), we_probe, we_attach
138 };
139 
140 #if NWE_ISAPNP
141 struct cfattach we_isapnp_ca = {
142 	sizeof(struct we_softc), we_probe, we_attach
143 };
144 #endif /* NWE_ISAPNP */
145 
146 #ifdef __NetBSD__
147 extern struct cfdriver we_cd;
148 #else
149 struct cfdriver we_cd = {
150 	NULL, "we", DV_IFNET
151 };
152 #endif
153 
154 const char *we_params __P((bus_space_tag_t, bus_space_handle_t, u_int8_t *,
155 	    bus_size_t *, int *, int *));
156 void	we_set_media __P((struct we_softc *, int));
157 
158 int	we_mediachange __P((struct dp8390_softc *));
159 void	we_mediastatus __P((struct dp8390_softc *, struct ifmediareq *));
160 
161 void	we_recv_int __P((struct dp8390_softc *));
162 void	we_init_card __P((struct dp8390_softc *));
163 int	we_write_mbuf __P((struct dp8390_softc *, struct mbuf *, int));
164 int	we_ring_copy __P((struct dp8390_softc *, int, caddr_t, u_short));
165 void	we_read_hdr __P((struct dp8390_softc *, int, struct dp8390_ring *));
166 int	we_test_mem __P((struct dp8390_softc *));
167 
168 __inline void we_readmem __P((struct we_softc *, int, u_int8_t *, int));
169 
170 static const int we_584_irq[] = {
171 	9, 3, 5, 7, 10, 11, 15, 4,
172 };
173 #define	NWE_584_IRQ	(sizeof(we_584_irq) / sizeof(we_584_irq[0]))
174 
175 static const int we_790_irq[] = {
176 	IRQUNK, 9, 3, 5, 7, 10, 11, 15,
177 };
178 #define	NWE_790_IRQ	(sizeof(we_790_irq) / sizeof(we_790_irq[0]))
179 
180 int we_media[] = {
181 	IFM_ETHER|IFM_10_2,
182 	IFM_ETHER|IFM_10_5,
183 };
184 #define	NWE_MEDIA	(sizeof(we_media) / sizeof(we_media[0]))
185 
186 /*
187  * Delay needed when switching 16-bit access to shared memory.
188  */
189 #define	WE_DELAY(wsc) delay(3)
190 
191 /*
192  * Enable card RAM, and 16-bit access.
193  */
194 #define	WE_MEM_ENABLE(wsc) \
195 do { \
196 	if ((wsc)->sc_16bitp) \
197 		bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \
198 		    WE_LAAR, (wsc)->sc_laar_proto | WE_LAAR_M16EN); \
199 	bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \
200 	    WE_MSR, wsc->sc_msr_proto | WE_MSR_MENB); \
201 	WE_DELAY((wsc)); \
202 } while (0)
203 
204 /*
205  * Disable card RAM, and 16-bit access.
206  */
207 #define	WE_MEM_DISABLE(wsc) \
208 do { \
209 	bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \
210 	    WE_MSR, (wsc)->sc_msr_proto); \
211 	if ((wsc)->sc_16bitp) \
212 		bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \
213 		    WE_LAAR, (wsc)->sc_laar_proto); \
214 	WE_DELAY((wsc)); \
215 } while (0)
216 
217 int
218 we_probe(parent, match, aux)
219 	struct device *parent;
220 	void *match, *aux;
221 {
222 	struct isa_attach_args *ia = aux;
223 	struct cfdata *cf = match;
224 	bus_space_tag_t asict, memt;
225 	bus_space_handle_t asich, memh;
226 	bus_size_t memsize;
227 	int asich_valid, memh_valid;
228 	int i, is790, rv = 0;
229 	u_int8_t x, type;
230 
231 	asict = ia->ia_iot;
232 	memt = ia->ia_memt;
233 
234 	asich_valid = memh_valid = 0;
235 
236 	/* Disallow wildcarded i/o addresses. */
237 	if (ia->ia_iobase == -1 /* ISACF_PORT_DEFAULT */)
238 		return (0);
239 
240 	/* Disallow wildcarded mem address. */
241 	if (ia->ia_maddr == -1 /* ISACF_IOMEM_DEFAULT */)
242 		return (0);
243 
244 	/* Attempt to map the device. */
245 	if (ia->ia_ioh)
246 		asich = ia->ia_ioh;
247 	else {
248 		if (bus_space_map(asict, ia->ia_iobase, WE_NPORTS, 0, &asich))
249 			goto out;
250 	}
251 	asich_valid = 1;
252 
253 #ifdef TOSH_ETHER
254 	bus_space_write_1(asict, asich, WE_MSR, WE_MSR_POW);
255 #endif
256 
257 	/*
258 	 * Attempt to do a checksum over the station address PROM.
259 	 * If it fails, it's probably not a WD/SMC board.  There is
260 	 * a problem with this, though.  Some clone WD8003E boards
261 	 * (e.g. Danpex) won't pass the checksum.  In this case,
262 	 * the checksum byte always seems to be 0.
263 	 */
264 	for (x = 0, i = 0; i < 8; i++)
265 		x += bus_space_read_1(asict, asich, WE_PROM + i);
266 
267 	if (x != WE_ROM_CHECKSUM_TOTAL) {
268 		/* Make sure it's an 8003E clone... */
269 		if (bus_space_read_1(asict, asich, WE_CARD_ID) !=
270 		    WE_TYPE_WD8003E)
271 			goto out;
272 
273 		/* Check the checksum byte. */
274 		if (bus_space_read_1(asict, asich, WE_PROM + 7) != 0)
275 			goto out;
276 	}
277 
278 	/*
279 	 * Reset the card to force it into a known state.
280 	 */
281 #ifdef TOSH_ETHER
282 	bus_space_write_1(asict, asich, WE_MSR, WE_MSR_RST | WE_MSR_POW);
283 #else
284 	bus_space_write_1(asict, asich, WE_MSR, WE_MSR_RST);
285 #endif
286 	delay(100);
287 
288 	bus_space_write_1(asict, asich, WE_MSR,
289 	    bus_space_read_1(asict, asich, WE_MSR) & ~WE_MSR_RST);
290 
291 	/* Wait in case the card is reading it's EEPROM. */
292 	delay(5000);
293 
294 	/*
295 	 * Get parameters.
296 	 */
297 	if (we_params(asict, asich, &type, &memsize, NULL, &is790) == NULL)
298 		goto out;
299 
300 	/* Allow user to override probed value. */
301 	if (ia->ia_msize)
302 		memsize = ia->ia_msize;
303 
304 	/* Attempt to map the memory space. */
305 	if (ia->ia_memh)
306 		memh = ia->ia_memh;
307 	else {
308 		if (bus_space_map(memt, ia->ia_maddr, memsize, 0, &memh))
309 			goto out;
310 	}
311 	memh_valid = 1;
312 
313 	/*
314 	 * If possible, get the assigned interrupt number from the card
315 	 * and use it.
316 	 */
317 	if (is790) {
318 		u_int8_t hwr;
319 
320 		/* Assemble together the encoded interrupt number. */
321 		hwr = bus_space_read_1(asict, asich, WE790_HWR);
322 		bus_space_write_1(asict, asich, WE790_HWR,
323 		    hwr | WE790_HWR_SWH);
324 
325 		x = bus_space_read_1(asict, asich, WE790_GCR);
326 		i = ((x & WE790_GCR_IR2) >> 4) |
327 		    ((x & (WE790_GCR_IR1|WE790_GCR_IR0)) >> 2);
328 		bus_space_write_1(asict, asich, WE790_HWR,
329 		    hwr & ~WE790_HWR_SWH);
330 
331 		if (ia->ia_irq != IRQUNK && ia->ia_irq != we_790_irq[i])
332 			printf("%s%d: overriding IRQ %d to %d\n",
333 			    we_cd.cd_name, cf->cf_unit, ia->ia_irq,
334 			    we_790_irq[i]);
335 		ia->ia_irq = we_790_irq[i];
336 	} else if (type & WE_SOFTCONFIG) {
337 		/* Assemble together the encoded interrupt number. */
338 		i = (bus_space_read_1(asict, asich, WE_ICR) & WE_ICR_IR2) |
339 		    ((bus_space_read_1(asict, asich, WE_IRR) &
340 		      (WE_IRR_IR0 | WE_IRR_IR1)) >> 5);
341 
342 		if (ia->ia_irq != IRQUNK && ia->ia_irq != we_584_irq[i])
343 			printf("%s%d: overriding IRQ %d to %d\n",
344 			    we_cd.cd_name, cf->cf_unit, ia->ia_irq,
345 			    we_584_irq[i]);
346 		ia->ia_irq = we_584_irq[i];
347 	}
348 
349 	/* So, we say we've found it! */
350 	ia->ia_iosize = WE_NPORTS;
351 	ia->ia_msize = memsize;
352 	rv = 1;
353 
354  out:
355 	if (asich_valid)
356 		bus_space_unmap(asict, asich, WE_NPORTS);
357 	if (memh_valid)
358 		bus_space_unmap(memt, memh, memsize);
359 	return (rv);
360 }
361 
362 void
363 we_attach(parent, self, aux)
364 	struct device *parent, *self;
365 	void *aux;
366 {
367 	struct we_softc *wsc = (struct we_softc *)self;
368 	struct dp8390_softc *sc = &wsc->sc_dp8390;
369 	struct isa_attach_args *ia = aux;
370 	bus_space_tag_t nict, asict, memt;
371 	bus_space_handle_t nich, asich, memh;
372 	const char *typestr;
373 	u_int8_t x;
374 	int i;
375 
376 	nict = asict = ia->ia_iot;
377 	memt = ia->ia_memt;
378 
379 	/* Map the device. */
380 	if (ia->ia_ioh)
381 		asich = ia->ia_ioh;
382 	else if (bus_space_map(asict, ia->ia_iobase, WE_NPORTS, 0, &asich)) {
383 		printf(": can't map nic i/o space\n");
384 		return;
385 	}
386 
387 	if (bus_space_subregion(asict, asich, WE_NIC_OFFSET, WE_NIC_NPORTS,
388 	    &nich)) {
389 		printf(": can't subregion i/o space\n");
390 		return;
391 	}
392 
393 	typestr = we_params(asict, asich, &wsc->sc_type, NULL,
394 	    &wsc->sc_16bitp, &sc->is790);
395 	if (typestr == NULL) {
396 		printf(": where did the card go?\n");
397 		return;
398 	}
399 
400 	/*
401 	 * Map memory space.  Note we use the size that might have
402 	 * been overridden by the user.
403 	 */
404 	if (ia->ia_memh)
405 		memh = ia->ia_memh;
406 	else if (bus_space_map(memt, ia->ia_maddr, ia->ia_msize, 0, &memh)) {
407 		printf(": can't map shared memory\n");
408 		return;
409 	}
410 
411 	/*
412 	 * Allow user to override 16-bit mode.  8-bit takes precedence.
413 	 */
414 	if (self->dv_cfdata->cf_flags & WE_FLAGS_FORCE_16BIT_MODE)
415 		wsc->sc_16bitp = 1;
416 	if (self->dv_cfdata->cf_flags & WE_FLAGS_FORCE_8BIT_MODE)
417 		wsc->sc_16bitp = 0;
418 
419 	wsc->sc_asict = asict;
420 	wsc->sc_asich = asich;
421 
422 	sc->sc_regt = nict;
423 	sc->sc_regh = nich;
424 
425 	sc->sc_buft = memt;
426 	sc->sc_bufh = memh;
427 
428 	/* Interface is always enabled. */
429 	sc->sc_enabled = 1;
430 
431 	/* Registers are linear. */
432 	for (i = 0; i < 16; i++)
433 		sc->sc_reg_map[i] = i;
434 
435 	/* Now we can use the NIC_{GET,PUT}() macros. */
436 
437 	printf(": %s (%s-bit)\n", typestr, wsc->sc_16bitp ? "16" : "8");
438 
439 	/* Get station address from EEPROM. */
440 	for (i = 0; i < ETHER_ADDR_LEN; i++)
441 #ifdef __NetBSD__
442 		sc->sc_enaddr[i] = bus_space_read_1(asict, asich, WE_PROM + i);
443 #else
444 		sc->sc_arpcom.ac_enaddr[i] =
445 		    bus_space_read_1(asict, asich, WE_PROM + i);
446 #endif
447 
448 	/*
449 	 * Set upper address bits and 8/16 bit access to shared memory.
450 	 */
451 	if (sc->is790) {
452 		wsc->sc_laar_proto =
453 		    bus_space_read_1(asict, asich, WE_LAAR) &
454 		    ~WE_LAAR_M16EN;
455 		bus_space_write_1(asict, asich, WE_LAAR,
456 		    wsc->sc_laar_proto | (wsc->sc_16bitp ? WE_LAAR_M16EN : 0));
457 	} else if ((wsc->sc_type & WE_SOFTCONFIG) ||
458 #ifdef TOSH_ETHER
459 	    (wsc->sc_type == WE_TYPE_TOSHIBA1) ||
460 	    (wsc->sc_type == WE_TYPE_TOSHIBA4) ||
461 #endif
462 	    (wsc->sc_type == WE_TYPE_WD8013EBT)) {
463 		wsc->sc_laar_proto = (ia->ia_maddr >> 19) & WE_LAAR_ADDRHI;
464 		if (wsc->sc_16bitp)
465 			wsc->sc_laar_proto |= WE_LAAR_L16EN;
466 		bus_space_write_1(asict, asich, WE_LAAR,
467 		    wsc->sc_laar_proto | (wsc->sc_16bitp ? WE_LAAR_M16EN : 0));
468 	}
469 
470 	/*
471 	 * Set address and enable interface shared memory.
472 	 */
473 	if (sc->is790) {
474 		/* XXX MAGIC CONSTANTS XXX */
475 		x = bus_space_read_1(asict, asich, 0x04);
476 		bus_space_write_1(asict, asich, 0x04, x | 0x80);
477 		bus_space_write_1(asict, asich, 0x0b,
478 		    ((ia->ia_maddr >> 13) & 0x0f) |
479 		    ((ia->ia_maddr >> 11) & 0x40) |
480 		    (bus_space_read_1(asict, asich, 0x0b) & 0xb0));
481 		bus_space_write_1(asict, asich, 0x04, x);
482 		wsc->sc_msr_proto = 0x00;
483 		sc->cr_proto = 0x00;
484 	} else {
485 #ifdef TOSH_ETHER
486 		if (wsc->sc_type == WE_TYPE_TOSHIBA1 ||
487 		    wsc->sc_type == WE_TYPE_TOSHIBA4) {
488 			bus_space_write_1(asict, asich, WE_MSR + 1,
489 			    ((ia->ia_maddr >> 8) & 0xe0) | 0x04);
490 			bus_space_write_1(asict, asich, WE_MSR + 2,
491 			    ((ia->ia_maddr >> 16) & 0x0f));
492 			wsc->sc_msr_proto = WE_MSR_POW;
493 		} else
494 #endif
495 			wsc->sc_msr_proto = (ia->ia_maddr >> 13) &
496 			    WE_MSR_ADDR;
497 
498 		sc->cr_proto = ED_CR_RD2;
499 	}
500 
501 	bus_space_write_1(asict, asich, WE_MSR,
502 	    wsc->sc_msr_proto | WE_MSR_MENB);
503 	WE_DELAY(wsc);
504 
505 	/*
506 	 * DCR gets:
507 	 *
508 	 *	FIFO threshold to 8, No auto-init Remote DMA,
509 	 *	byte order=80x86.
510 	 *
511 	 * 16-bit cards also get word-wide DMA transfers.
512 	 */
513 	sc->dcr_reg = ED_DCR_FT1 | ED_DCR_LS |
514 	    (wsc->sc_16bitp ? ED_DCR_WTS : 0);
515 
516 	sc->test_mem = we_test_mem;
517 	sc->ring_copy = we_ring_copy;
518 	sc->write_mbuf = we_write_mbuf;
519 	sc->read_hdr = we_read_hdr;
520 	sc->recv_int = we_recv_int;
521 
522 	sc->sc_mediachange = we_mediachange;
523 	sc->sc_mediastatus = we_mediastatus;
524 
525 	sc->mem_start = 0;
526 	sc->mem_size = ia->ia_msize;
527 
528 	sc->sc_flags = self->dv_cfdata->cf_flags;
529 
530 	/* Do generic parts of attach. */
531 	if (wsc->sc_type & WE_SOFTCONFIG) {
532 		int defmedia = IFM_ETHER;
533 
534 		if (sc->is790) {
535 			x = bus_space_read_1(asict, asich, WE790_HWR);
536 			bus_space_write_1(asict, asich, WE790_HWR,
537 			    x | WE790_HWR_SWH);
538 			if (bus_space_read_1(asict, asich, WE790_GCR) &
539 			    WE790_GCR_GPOUT)
540 				defmedia |= IFM_10_2;
541 			else
542 				defmedia |= IFM_10_5;
543 			bus_space_write_1(asict, asich, WE790_HWR,
544 			    x & ~WE790_HWR_SWH);
545 		} else {
546 			x = bus_space_read_1(asict, asich, WE_IRR);
547 			if (x & WE_IRR_OUT2)
548 				defmedia |= IFM_10_2;
549 			else
550 				defmedia |= IFM_10_5;
551 		}
552 		i = dp8390_config(sc, we_media, NWE_MEDIA, defmedia);
553 	} else
554 		i = dp8390_config(sc, NULL, 0, 0);
555 	if (i) {
556 		printf("%s: configuration failed\n", sc->sc_dev.dv_xname);
557 		return;
558 	}
559 
560 	/*
561 	 * Disable 16-bit access to shared memory - we leave it disabled
562 	 * so that:
563 	 *
564 	 *	(1) machines reboot properly when the board is set to
565 	 *	    16-bit mode and there are conflicting 8-bit devices
566 	 *	    within the same 128k address space as this board's
567 	 *	    shared memory, and
568 	 *
569 	 *	(2) so that other 8-bit devices with shared memory
570 	 *	    in this same 128k address space will work.
571 	 */
572 	WE_MEM_DISABLE(wsc);
573 
574 	/*
575 	 * Enable the configured interrupt.
576 	 */
577 	if (sc->is790)
578 		bus_space_write_1(asict, asich, WE790_ICR,
579 		    bus_space_read_1(asict, asich, WE790_ICR) |
580 		    WE790_ICR_EIL);
581 	else if (wsc->sc_type & WE_SOFTCONFIG)
582 		bus_space_write_1(asict, asich, WE_IRR,
583 		    bus_space_read_1(asict, asich, WE_IRR) | WE_IRR_IEN);
584 	else if (ia->ia_irq == IRQUNK) {
585 		printf("%s: can't wildcard IRQ on a %s\n",
586 		    sc->sc_dev.dv_xname, typestr);
587 		return;
588 	}
589 
590 	/* Establish interrupt handler. */
591 	wsc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
592 	    IPL_NET, dp8390_intr, sc, sc->sc_dev.dv_xname);
593 	if (wsc->sc_ih == NULL)
594 		printf("%s: can't establish interrupt\n", sc->sc_dev.dv_xname);
595 }
596 
597 int
598 we_test_mem(sc)
599 	struct dp8390_softc *sc;
600 {
601 	struct we_softc *wsc = (struct we_softc *)sc;
602 	bus_space_tag_t memt = sc->sc_buft;
603 	bus_space_handle_t memh = sc->sc_bufh;
604 	bus_size_t memsize = sc->mem_size;
605 	int i;
606 
607 	if (wsc->sc_16bitp)
608 		bus_space_set_region_2(memt, memh, 0, 0, memsize >> 1);
609 	else
610 		bus_space_set_region_1(memt, memh, 0, 0, memsize);
611 
612 	if (wsc->sc_16bitp) {
613 		for (i = 0; i < memsize; i += 2) {
614 			if (bus_space_read_2(memt, memh, i) != 0)
615 				goto fail;
616 		}
617 	} else {
618 		for (i = 0; i < memsize; i++) {
619 			if (bus_space_read_1(memt, memh, i) != 0)
620 				goto fail;
621 		}
622 	}
623 
624 	return (0);
625 
626  fail:
627 	printf("%s: failed to clear shared memory at offset 0x%x\n",
628 	    sc->sc_dev.dv_xname, i);
629 	WE_MEM_DISABLE(wsc);
630 	return (1);
631 }
632 
633 /*
634  * Given a NIC memory source address and a host memory destination address,
635  * copy 'len' from NIC to host using shared memory.  The 'len' is rounded
636  * up to a word - ok as long as mbufs are word-sized.
637  */
638 __inline void
639 we_readmem(wsc, from, to, len)
640 	struct we_softc *wsc;
641 	int from;
642 	u_int8_t *to;
643 	int len;
644 {
645 	bus_space_tag_t memt = wsc->sc_dp8390.sc_buft;
646 	bus_space_handle_t memh = wsc->sc_dp8390.sc_bufh;
647 
648 	if (len & 1)
649 		++len;
650 
651 	if (wsc->sc_16bitp)
652 		bus_space_read_region_stream_2(memt, memh, from,
653 		    (u_int16_t *)to, len >> 1);
654 	else
655 		bus_space_read_region_1(memt, memh, from,
656 		    to, len);
657 }
658 
659 int
660 we_write_mbuf(sc, m, buf)
661 	struct dp8390_softc *sc;
662 	struct mbuf *m;
663 	int buf;
664 {
665 	struct we_softc *wsc = (struct we_softc *)sc;
666 	bus_space_tag_t memt = wsc->sc_dp8390.sc_buft;
667 	bus_space_handle_t memh = wsc->sc_dp8390.sc_bufh;
668 	u_int8_t *data, savebyte[2];
669 	int savelen, len, leftover;
670 #ifdef DIAGNOSTIC
671 	u_int8_t *lim;
672 #endif
673 
674 	savelen = m->m_pkthdr.len;
675 
676 	WE_MEM_ENABLE(wsc);
677 
678 	/*
679 	 * 8-bit boards are simple; no alignment tricks are necessary.
680 	 */
681 	if (wsc->sc_16bitp == 0) {
682 		for (; m != NULL; buf += m->m_len, m = m->m_next)
683 			bus_space_write_region_1(memt, memh,
684 			    buf, mtod(m, u_int8_t *), m->m_len);
685 		goto out;
686 	}
687 
688 	/* Start out with no leftover data. */
689 	leftover = 0;
690 	savebyte[0] = savebyte[1] = 0;
691 
692 	for (; m != NULL; m = m->m_next) {
693 		len = m->m_len;
694 		if (len == 0)
695 			continue;
696 		data = mtod(m, u_int8_t *);
697 #ifdef DIAGNOSTIC
698 		lim = data + len;
699 #endif
700 		while (len > 0) {
701 			if (leftover) {
702 				/*
703 				 * Data left over (from mbuf or realignment).
704 				 * Buffer the next byte, and write it and
705 				 * the leftover data out.
706 				 */
707 				savebyte[1] = *data++;
708 				len--;
709 				bus_space_write_stream_2(memt, memh, buf,
710 				    *(u_int16_t *)savebyte);
711 				buf += 2;
712 				leftover = 0;
713 #ifdef i386
714 #define ALIGNED_POINTER(p,t)	1
715 #endif
716 #ifdef alpha
717 #define ALIGNED_POINTER(p,t)	((((u_long)(p)) & (sizeof(t)-1)) == 0)
718 #endif
719 			} else if (ALIGNED_POINTER(data, u_int16_t) == 0) {
720 				/*
721 				 * Unaligned dta; buffer the next byte.
722 				 */
723 				savebyte[0] = *data++;
724 				len--;
725 				leftover = 1;
726 			} else {
727 				/*
728 				 * Aligned data; output contiguous words as
729 				 * much as we can, then buffer the remaining
730 				 * byte, if any.
731 				 */
732 				leftover = len & 1;
733 				len &= ~1;
734 				bus_space_write_region_stream_2(memt, memh,
735 				    buf, (u_int16_t *)data, len >> 1);
736 				data += len;
737 				buf += len;
738 				if (leftover)
739 					savebyte[0] = *data++;
740 				len = 0;
741 			}
742 		}
743 		if (len < 0)
744 			panic("we_write_mbuf: negative len");
745 #ifdef DIAGNOSTIC
746 		if (data != lim)
747 			panic("we_write_mbuf: data != lim");
748 #endif
749 	}
750 	if (leftover) {
751 		savebyte[1] = 0;
752 		bus_space_write_stream_2(memt, memh, buf,
753 		    *(u_int16_t *)savebyte);
754 	}
755 
756  out:
757 	WE_MEM_DISABLE(wsc);
758 
759 	return (savelen);
760 }
761 
762 int
763 we_ring_copy(sc, src, dst, amount)
764 	struct dp8390_softc *sc;
765 	int src;
766 	caddr_t dst;
767 	u_short amount;
768 {
769 	struct we_softc *wsc = (struct we_softc *)sc;
770 	u_short tmp_amount;
771 
772 	/* Does copy wrap to lower addr in ring buffer? */
773 	if (src + amount > sc->mem_end) {
774 		tmp_amount = sc->mem_end - src;
775 
776 		/* Copy amount up to end of NIC memory. */
777 		we_readmem(wsc, src, dst, tmp_amount);
778 
779 		amount -= tmp_amount;
780 		src = sc->mem_ring;
781 		dst += tmp_amount;
782 	}
783 
784 	we_readmem(wsc, src, dst, amount);
785 
786 	return (src + amount);
787 }
788 
789 void
790 we_read_hdr(sc, packet_ptr, packet_hdrp)
791 	struct dp8390_softc *sc;
792 	int packet_ptr;
793 	struct dp8390_ring *packet_hdrp;
794 {
795 	struct we_softc *wsc = (struct we_softc *)sc;
796 
797 	we_readmem(wsc, packet_ptr, (u_int8_t *)packet_hdrp,
798 	    sizeof(struct dp8390_ring));
799 #if BYTE_ORDER == BIG_ENDIAN
800 	packet_hdrp->count = swap16(packet_hdrp->count);
801 #endif
802 }
803 
804 void
805 we_recv_int(sc)
806 	struct dp8390_softc *sc;
807 {
808 	struct we_softc *wsc = (struct we_softc *)sc;
809 
810 	WE_MEM_ENABLE(wsc);
811 	dp8390_rint(sc);
812 	WE_MEM_DISABLE(wsc);
813 }
814 
815 int
816 we_mediachange(sc)
817 	struct dp8390_softc *sc;
818 {
819 
820 	/*
821 	 * Current media is already set up.  Just reset the interface
822 	 * to let the new value take hold.  The new media will be
823 	 * set up in we_init_card() called via dp8390_init().
824 	 */
825 	dp8390_reset(sc);
826 	return (0);
827 }
828 
829 void
830 we_mediastatus(sc, ifmr)
831 	struct dp8390_softc *sc;
832 	struct ifmediareq *ifmr;
833 {
834 	struct ifmedia *ifm = &sc->sc_media;
835 
836 	/*
837 	 * The currently selected media is always the active media.
838 	 */
839 	ifmr->ifm_active = ifm->ifm_cur->ifm_media;
840 }
841 
842 void
843 we_init_card(sc)
844 	struct dp8390_softc *sc;
845 {
846 	struct we_softc *wsc = (struct we_softc *)sc;
847 	struct ifmedia *ifm = &sc->sc_media;
848 
849 	we_set_media(wsc, ifm->ifm_cur->ifm_media);
850 }
851 
852 void
853 we_set_media(wsc, media)
854 	struct we_softc *wsc;
855 	int media;
856 {
857 	struct dp8390_softc *sc = &wsc->sc_dp8390;
858 	bus_space_tag_t asict = wsc->sc_asict;
859 	bus_space_handle_t asich = wsc->sc_asich;
860 	u_int8_t hwr, gcr, irr;
861 
862 	if (sc->is790) {
863 		hwr = bus_space_read_1(asict, asich, WE790_HWR);
864 		bus_space_write_1(asict, asich, WE790_HWR,
865 		    hwr | WE790_HWR_SWH);
866 		gcr = bus_space_read_1(asict, asich, WE790_GCR);
867 		if (IFM_SUBTYPE(media) == IFM_10_2)
868 			gcr |= WE790_GCR_GPOUT;
869 		else
870 			gcr &= ~WE790_GCR_GPOUT;
871 		bus_space_write_1(asict, asich, WE790_GCR,
872 		    gcr | WE790_GCR_LIT);
873 		bus_space_write_1(asict, asich, WE790_HWR,
874 		    hwr & ~WE790_HWR_SWH);
875 		return;
876 	}
877 
878 	irr = bus_space_read_1(wsc->sc_asict, wsc->sc_asich, WE_IRR);
879 	if (IFM_SUBTYPE(media) == IFM_10_2)
880 		irr |= WE_IRR_OUT2;
881 	else
882 		irr &= ~WE_IRR_OUT2;
883 	bus_space_write_1(wsc->sc_asict, wsc->sc_asich, WE_IRR, irr);
884 }
885 
886 const char *
887 we_params(asict, asich, typep, memsizep, is16bitp, is790p)
888 	bus_space_tag_t asict;
889 	bus_space_handle_t asich;
890 	u_int8_t *typep;
891 	bus_size_t *memsizep;
892 	int *is16bitp, *is790p;
893 {
894 	const char *typestr;
895 	bus_size_t memsize;
896 	int is16bit, is790;
897 	u_int8_t type;
898 
899 	memsize = 8192;
900 	is16bit = is790 = 0;
901 
902 	type = bus_space_read_1(asict, asich, WE_CARD_ID);
903 	switch (type) {
904 	case WE_TYPE_WD8003S:
905 		typestr = "WD8003S";
906 		break;
907 	case WE_TYPE_WD8003E:
908 		typestr = "WD8003E";
909 		break;
910 	case WE_TYPE_WD8003EB:
911 		typestr = "WD8003EB";
912 		break;
913 	case WE_TYPE_WD8003W:
914 		typestr = "WD8003W";
915 		break;
916 	case WE_TYPE_WD8013EBT:
917 		typestr = "WD8013EBT";
918 		memsize = 16384;
919 		is16bit = 1;
920 		break;
921 	case WE_TYPE_WD8013W:
922 		typestr = "WD8013W";
923 		memsize = 16384;
924 		is16bit = 1;
925 		break;
926 	case WE_TYPE_WD8013EP:		/* also WD8003EP */
927 		if (bus_space_read_1(asict, asich, WE_ICR) & WE_ICR_16BIT) {
928 			is16bit = 1;
929 			memsize = 16384;
930 			typestr = "WD8013EP";
931 		} else
932 			typestr = "WD8003EP";
933 		break;
934 	case WE_TYPE_WD8013WC:
935 		typestr = "WD8013WC";
936 		memsize = 16384;
937 		is16bit = 1;
938 		break;
939 	case WE_TYPE_WD8013EBP:
940 		typestr = "WD8013EBP";
941 		memsize = 16384;
942 		is16bit = 1;
943 		break;
944 	case WE_TYPE_WD8013EPC:
945 		typestr = "WD8013EPC";
946 		memsize = 16384;
947 		is16bit = 1;
948 		break;
949 	case WE_TYPE_SMC8216C:
950 	case WE_TYPE_SMC8216T:
951 	    {
952 		u_int8_t hwr;
953 
954 		typestr = (type == WE_TYPE_SMC8216C) ?
955 		    "SMC8216/SMC8216C" : "SMC8216T";
956 
957 		hwr = bus_space_read_1(asict, asich, WE790_HWR);
958 		bus_space_write_1(asict, asich, WE790_HWR,
959 		    hwr | WE790_HWR_SWH);
960 		switch (bus_space_read_1(asict, asich, WE790_RAR) &
961 		    WE790_RAR_SZ64) {
962 		case WE790_RAR_SZ64:
963 			memsize = 65536;
964 			break;
965 		case WE790_RAR_SZ32:
966 			memsize = 32768;
967 			break;
968 		case WE790_RAR_SZ16:
969 			memsize = 16384;
970 			break;
971 		case WE790_RAR_SZ8:
972 			/* 8216 has 16K shared mem -- 8416 has 8K */
973 			typestr = (type == WE_TYPE_SMC8216C) ?
974 			    "SMC8416C/SMC8416BT" : "SMC8416T";
975 			memsize = 8192;
976 			break;
977 		}
978 		bus_space_write_1(asict, asich, WE790_HWR, hwr);
979 
980 		is16bit = 1;
981 		is790 = 1;
982 		break;
983 	    }
984 #ifdef TOSH_ETHER
985 	case WE_TYPE_TOSHIBA1:
986 		typestr = "Toshiba1";
987 		memsize = 32768;
988 		is16bit = 1;
989 		break;
990 	case WE_TYPE_TOSHIBA4:
991 		typestr = "Toshiba4";
992 		memsize = 32768;
993 		is16bit = 1;
994 		break;
995 #endif
996 	default:
997 		/* Not one we recognize. */
998 		return (NULL);
999 	}
1000 
1001 	/*
1002 	 * Make some adjustments to initial values depending on what is
1003 	 * found in the ICR.
1004 	 */
1005 	if (is16bit && (type != WE_TYPE_WD8013EBT) &&
1006 #ifdef TOSH_ETHER
1007 	    (type != WE_TYPE_TOSHIBA1 && type != WE_TYPE_TOSHIBA4) &&
1008 #endif
1009 	    (bus_space_read_1(asict, asich, WE_ICR) & WE_ICR_16BIT) == 0) {
1010 		is16bit = 0;
1011 		memsize = 8192;
1012 	}
1013 
1014 #ifdef WE_DEBUG
1015 	{
1016 		int i;
1017 
1018 		printf("we_params: type = 0x%x, typestr = %s, is16bit = %d, "
1019 		    "memsize = %d\n", type, typestr, is16bit, memsize);
1020 		for (i = 0; i < 8; i++)
1021 			printf("     %d -> 0x%x\n", i,
1022 			    bus_space_read_1(asict, asich, i));
1023 	}
1024 #endif
1025 
1026 	if (typep != NULL)
1027 		*typep = type;
1028 	if (memsizep != NULL)
1029 		*memsizep = memsize;
1030 	if (is16bitp != NULL)
1031 		*is16bitp = is16bit;
1032 	if (is790p != NULL)
1033 		*is790p = is790;
1034 	return (typestr);
1035 }
1036