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