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