xref: /netbsd-src/sys/dev/ic/we.c (revision 8058413106db4da60769583b1e0d575046b1ecfb)
1 /*	$NetBSD: we.c,v 1.17 2010/03/19 15:59:22 tsutsui Exp $	*/
2 
3 /*-
4  * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9  * NASA Ames Research Center.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * Device driver for National Semiconductor DS8390/WD83C690 based ethernet
35  * adapters.
36  *
37  * Copyright (c) 1994, 1995 Charles M. Hannum.  All rights reserved.
38  *
39  * Copyright (C) 1993, David Greenman.  This software may be used, modified,
40  * copied, distributed, and sold, in both source and binary form provided that
41  * the above copyright and these terms are retained.  Under no circumstances is
42  * the author responsible for the proper functioning of this software, nor does
43  * the author assume any responsibility for damages incurred with its use.
44  */
45 
46 /*
47  * Device driver for the Western Digital/SMC 8003 and 8013 series,
48  * and the SMC Elite Ultra (8216).
49  */
50 
51 #include <sys/cdefs.h>
52 __KERNEL_RCSID(0, "$NetBSD: we.c,v 1.17 2010/03/19 15:59:22 tsutsui Exp $");
53 
54 #include <sys/param.h>
55 #include <sys/systm.h>
56 #include <sys/device.h>
57 #include <sys/socket.h>
58 #include <sys/mbuf.h>
59 #include <sys/syslog.h>
60 
61 #include <net/if.h>
62 #include <net/if_dl.h>
63 #include <net/if_types.h>
64 #include <net/if_media.h>
65 
66 #include <net/if_ether.h>
67 
68 #include <sys/bus.h>
69 #include <sys/bswap.h>
70 #include <sys/intr.h>
71 
72 #include <dev/isa/isareg.h>
73 #include <dev/isa/isavar.h>
74 
75 #include <dev/ic/dp8390reg.h>
76 #include <dev/ic/dp8390var.h>
77 #include <dev/ic/wereg.h>
78 #include <dev/ic/wevar.h>
79 
80 #ifndef __BUS_SPACE_HAS_STREAM_METHODS
81 #define	bus_space_read_region_stream_2	bus_space_read_region_2
82 #define	bus_space_write_stream_2	bus_space_write_2
83 #define	bus_space_write_region_stream_2	bus_space_write_region_2
84 #endif
85 
86 static void	we_set_media(struct we_softc *, int);
87 
88 static void	we_media_init(struct dp8390_softc *);
89 
90 static int	we_mediachange(struct dp8390_softc *);
91 static void	we_mediastatus(struct dp8390_softc *, struct ifmediareq *);
92 
93 static void	we_recv_int(struct dp8390_softc *);
94 static void	we_init_card(struct dp8390_softc *);
95 static int	we_write_mbuf(struct dp8390_softc *, struct mbuf *, int);
96 static int	we_ring_copy(struct dp8390_softc *, int, void *, u_short);
97 static void	we_read_hdr(struct dp8390_softc *, int, struct dp8390_ring *);
98 static int	we_test_mem(struct dp8390_softc *);
99 
100 static inline void we_readmem(struct we_softc *, int, uint8_t *, int);
101 
102 /*
103  * Delay needed when switching 16-bit access to shared memory.
104  */
105 #define	WE_DELAY(wsc) delay(3)
106 
107 /*
108  * Enable card RAM, and 16-bit access.
109  */
110 #define	WE_MEM_ENABLE(wsc) \
111 if (((wsc)->sc_flags & WE_16BIT_NOTOGGLE) == 0) {			\
112 	if ((wsc)->sc_flags & WE_16BIT_ENABLE)				\
113 		bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich,	\
114 		    WE_LAAR, (wsc)->sc_laar_proto | WE_LAAR_M16EN);	\
115 	bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich,		\
116 	    WE_MSR, wsc->sc_msr_proto | WE_MSR_MENB);			\
117 	WE_DELAY((wsc));						\
118 }
119 
120 /*
121  * Disable card RAM, and 16-bit access.
122  */
123 #define	WE_MEM_DISABLE(wsc) \
124 if (((wsc)->sc_flags & WE_16BIT_NOTOGGLE) == 0) {			\
125 	bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich,		\
126 	    WE_MSR, (wsc)->sc_msr_proto);				\
127 	if ((wsc)->sc_flags & WE_16BIT_ENABLE)				\
128 		bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich,	\
129 		    WE_LAAR, (wsc)->sc_laar_proto);			\
130 	WE_DELAY((wsc));						\
131 }
132 
133 int
we_config(device_t self,struct we_softc * wsc,const char * typestr)134 we_config(device_t self, struct we_softc *wsc, const char *typestr)
135 {
136 	struct dp8390_softc *sc = &wsc->sc_dp8390;
137 	uint8_t x;
138 	int i, forced_16bit = 0;
139 
140 	/*
141 	 * Allow user to override 16-bit mode.  8-bit takes precedence.
142 	 */
143 	if (device_cfdata(self)->cf_flags & DP8390_FORCE_16BIT_MODE) {
144 		wsc->sc_flags |= WE_16BIT_ENABLE;
145 		forced_16bit = 1;
146 	}
147 	if (device_cfdata(self)->cf_flags & DP8390_FORCE_8BIT_MODE)
148 		wsc->sc_flags &= ~WE_16BIT_ENABLE;
149 
150 	/* Registers are linear. */
151 	for (i = 0; i < 16; i++)
152 		sc->sc_reg_map[i] = i;
153 
154 	/* Now we can use the NIC_{GET,PUT}() macros. */
155 
156 	aprint_normal_dev(self, "%s Ethernet (%s-bit)\n",
157 	    typestr, wsc->sc_flags & WE_16BIT_ENABLE ? "16" : "8");
158 
159 	/* Get station address from EEPROM. */
160 	for (i = 0; i < ETHER_ADDR_LEN; i++)
161 		sc->sc_enaddr[i] =
162 		    bus_space_read_1(wsc->sc_asict, wsc->sc_asich, WE_PROM + i);
163 
164 	/*
165 	 * Set upper address bits and 8/16 bit access to shared memory.
166 	 */
167 	if (sc->is790) {
168 		wsc->sc_laar_proto =
169 		    bus_space_read_1(wsc->sc_asict, wsc->sc_asich, WE_LAAR) &
170 		    ~WE_LAAR_M16EN;
171 		bus_space_write_1(wsc->sc_asict, wsc->sc_asich, WE_LAAR,
172 		    wsc->sc_laar_proto |
173 		    (wsc->sc_flags & WE_16BIT_ENABLE ? WE_LAAR_M16EN : 0));
174 	} else if ((wsc->sc_type & WE_SOFTCONFIG) ||
175 #ifdef TOSH_ETHER
176 	    (wsc->sc_type == WE_TYPE_TOSHIBA1) ||
177 	    (wsc->sc_type == WE_TYPE_TOSHIBA4) ||
178 #endif
179 	    (forced_16bit) ||
180 	    (wsc->sc_type == WE_TYPE_WD8013EBT)) {
181 		wsc->sc_laar_proto = (wsc->sc_maddr >> 19) & WE_LAAR_ADDRHI;
182 		if (wsc->sc_flags & WE_16BIT_ENABLE)
183 			wsc->sc_laar_proto |= WE_LAAR_L16EN;
184 		bus_space_write_1(wsc->sc_asict, wsc->sc_asich, WE_LAAR,
185 		    wsc->sc_laar_proto |
186 		    (wsc->sc_flags & WE_16BIT_ENABLE ? WE_LAAR_M16EN : 0));
187 	}
188 
189 	/*
190 	 * Set address and enable interface shared memory.
191 	 */
192 	if (sc->is790) {
193 		x = bus_space_read_1(wsc->sc_asict, wsc->sc_asich, WE790_HWR);
194 		bus_space_write_1(wsc->sc_asict, wsc->sc_asich,
195 		    WE790_HWR, x | WE790_HWR_SWH);
196 		bus_space_write_1(wsc->sc_asict, wsc->sc_asich, WE790_RAR,
197 		    ((wsc->sc_maddr >> WE790_RAR_OFF_SHIFT) & WE790_RAR_OFF) |
198 		    ((wsc->sc_maddr & (1 << WE790_RAR_BASE_SHIFT)) != 0 ?
199 		     WE790_RAR_BASE1 : WE790_RAR_BASE0) |
200 		    (bus_space_read_1(wsc->sc_asict, wsc->sc_asich, WE790_RAR) &
201 		     ~(WE790_RAR_OFF | WE790_RAR_BASE)));
202 		bus_space_write_1(wsc->sc_asict, wsc->sc_asich, WE790_HWR, x);
203 		wsc->sc_msr_proto = 0x00;
204 		sc->cr_proto = 0x00;
205 	} else {
206 #ifdef TOSH_ETHER
207 		if (wsc->sc_type == WE_TYPE_TOSHIBA1 ||
208 		    wsc->sc_type == WE_TYPE_TOSHIBA4) {
209 			/* XXX MAGIC CONSTANTS XXX */
210 			bus_space_write_1(wsc->sc_asict, wsc->sc_asich,
211 			    WE_MSR + 1,
212 			    ((wsc->sc_maddr >> 8) & 0xe0) | 0x04);
213 			bus_space_write_1(wsc->sc_asict, wsc->sc_asich,
214 			    WE_MSR + 2,
215 			    ((wsc->sc_maddr >> 16) & 0x0f));
216 			wsc->sc_msr_proto = WE_MSR_POW;
217 		} else
218 #endif
219 			wsc->sc_msr_proto = (wsc->sc_maddr >> 13) &
220 			    WE_MSR_ADDR;
221 
222 		sc->cr_proto = ED_CR_RD2;
223 	}
224 
225 	bus_space_write_1(wsc->sc_asict, wsc->sc_asich, WE_MSR,
226 	    wsc->sc_msr_proto | WE_MSR_MENB);
227 	WE_DELAY(wsc);
228 
229 	/*
230 	 * DCR gets:
231 	 *
232 	 *	FIFO threshold to 8, No auto-init Remote DMA,
233 	 *	byte order=80x86.
234 	 *
235 	 * 16-bit cards also get word-wide DMA transfers.
236 	 */
237 	sc->dcr_reg = ED_DCR_FT1 | ED_DCR_LS |
238 	    (wsc->sc_flags & WE_16BIT_ENABLE ? ED_DCR_WTS : 0);
239 
240 	sc->test_mem = we_test_mem;
241 	sc->ring_copy = we_ring_copy;
242 	sc->write_mbuf = we_write_mbuf;
243 	sc->read_hdr = we_read_hdr;
244 	sc->recv_int = we_recv_int;
245 	sc->init_card = we_init_card;
246 
247 	sc->sc_mediachange = we_mediachange;
248 	sc->sc_mediastatus = we_mediastatus;
249 
250 	sc->mem_start = 0;
251 	/* sc->mem_size has to be set by frontend */
252 
253 	sc->sc_flags = device_cfdata(self)->cf_flags;
254 
255 	/* Do generic parts of attach. */
256 	if (wsc->sc_type & WE_SOFTCONFIG)
257 		sc->sc_media_init = we_media_init;
258 	else
259 		sc->sc_media_init = dp8390_media_init;
260 	if (dp8390_config(sc)) {
261 		aprint_error_dev(self, "configuration failed\n");
262 		return 1;
263 	}
264 
265 	/*
266 	 * Disable 16-bit access to shared memory - we leave it disabled
267 	 * so that:
268 	 *
269 	 *	(1) machines reboot properly when the board is set to
270 	 *	    16-bit mode and there are conflicting 8-bit devices
271 	 *	    within the same 128k address space as this board's
272 	 *	    shared memory, and
273 	 *
274 	 *	(2) so that other 8-bit devices with shared memory
275 	 *	    in this same 128k address space will work.
276 	 */
277 	WE_MEM_DISABLE(wsc);
278 
279 	return 0;
280 }
281 
282 static int
we_test_mem(struct dp8390_softc * sc)283 we_test_mem(struct dp8390_softc *sc)
284 {
285 	struct we_softc *wsc = (struct we_softc *)sc;
286 	bus_space_tag_t memt = sc->sc_buft;
287 	bus_space_handle_t memh = sc->sc_bufh;
288 	bus_size_t memsize = sc->mem_size;
289 	int i;
290 
291 	if (wsc->sc_flags & WE_16BIT_ENABLE)
292 		bus_space_set_region_2(memt, memh, 0, 0, memsize >> 1);
293 	else
294 		bus_space_set_region_1(memt, memh, 0, 0, memsize);
295 
296 	if (wsc->sc_flags & WE_16BIT_ENABLE) {
297 		for (i = 0; i < memsize; i += 2) {
298 			if (bus_space_read_2(memt, memh, i) != 0)
299 				goto fail;
300 		}
301 	} else {
302 		for (i = 0; i < memsize; i++) {
303 			if (bus_space_read_1(memt, memh, i) != 0)
304 				goto fail;
305 		}
306 	}
307 
308 	return 0;
309 
310  fail:
311 	aprint_error_dev(sc->sc_dev,
312 	    "failed to clear shared memory at offset 0x%x\n", i);
313 	WE_MEM_DISABLE(wsc);
314 	return 1;
315 }
316 
317 /*
318  * Given a NIC memory source address and a host memory destination address,
319  * copy 'len' from NIC to host using shared memory.  The 'len' is rounded
320  * up to a word - ok as long as mbufs are word-sized.
321  */
322 static inline void
we_readmem(struct we_softc * wsc,int from,uint8_t * to,int len)323 we_readmem(struct we_softc *wsc, int from, uint8_t *to, int len)
324 {
325 	bus_space_tag_t memt = wsc->sc_dp8390.sc_buft;
326 	bus_space_handle_t memh = wsc->sc_dp8390.sc_bufh;
327 
328 	if (len & 1)
329 		++len;
330 
331 	if (wsc->sc_flags & WE_16BIT_ENABLE)
332 		bus_space_read_region_stream_2(memt, memh, from,
333 		    (uint16_t *)to, len >> 1);
334 	else
335 		bus_space_read_region_1(memt, memh, from,
336 		    to, len);
337 }
338 
339 static int
we_write_mbuf(struct dp8390_softc * sc,struct mbuf * m,int buf)340 we_write_mbuf(struct dp8390_softc *sc, struct mbuf *m, int buf)
341 {
342 	struct we_softc *wsc = (struct we_softc *)sc;
343 	bus_space_tag_t memt = wsc->sc_dp8390.sc_buft;
344 	bus_space_handle_t memh = wsc->sc_dp8390.sc_bufh;
345 	uint8_t *data, savebyte[2];
346 	int savelen, len, leftover;
347 #ifdef DIAGNOSTIC
348 	uint8_t *lim;
349 #endif
350 
351 	savelen = m->m_pkthdr.len;
352 
353 	WE_MEM_ENABLE(wsc);
354 
355 	/*
356 	 * 8-bit boards are simple; no alignment tricks are necessary.
357 	 */
358 	if ((wsc->sc_flags & WE_16BIT_ENABLE) == 0) {
359 		for (; m != NULL; buf += m->m_len, m = m->m_next)
360 			bus_space_write_region_1(memt, memh,
361 			    buf, mtod(m, uint8_t *), m->m_len);
362 		if (savelen < ETHER_MIN_LEN - ETHER_CRC_LEN) {
363 			bus_space_set_region_1(memt, memh,
364 			    buf, 0, ETHER_MIN_LEN - ETHER_CRC_LEN - savelen);
365 			savelen = ETHER_MIN_LEN - ETHER_CRC_LEN;
366 		}
367 		goto out;
368 	}
369 
370 	/* Start out with no leftover data. */
371 	leftover = 0;
372 	savebyte[0] = savebyte[1] = 0;
373 
374 	for (; m != NULL; m = m->m_next) {
375 		len = m->m_len;
376 		if (len == 0)
377 			continue;
378 		data = mtod(m, uint8_t *);
379 #ifdef DIAGNOSTIC
380 		lim = data + len;
381 #endif
382 		while (len > 0) {
383 			if (leftover) {
384 				/*
385 				 * Data left over (from mbuf or realignment).
386 				 * Buffer the next byte, and write it and
387 				 * the leftover data out.
388 				 */
389 				savebyte[1] = *data++;
390 				len--;
391 				bus_space_write_stream_2(memt, memh, buf,
392 				    *(uint16_t *)savebyte);
393 				buf += 2;
394 				leftover = 0;
395 			} else if (BUS_SPACE_ALIGNED_POINTER(data, uint16_t)
396 			    == 0) {
397 				/*
398 				 * Unaligned dta; buffer the next byte.
399 				 */
400 				savebyte[0] = *data++;
401 				len--;
402 				leftover = 1;
403 			} else {
404 				/*
405 				 * Aligned data; output contiguous words as
406 				 * much as we can, then buffer the remaining
407 				 * byte, if any.
408 				 */
409 				leftover = len & 1;
410 				len &= ~1;
411 				bus_space_write_region_stream_2(memt, memh,
412 				    buf, (uint16_t *)data, len >> 1);
413 				data += len;
414 				buf += len;
415 				if (leftover)
416 					savebyte[0] = *data++;
417 				len = 0;
418 			}
419 		}
420 		if (len < 0)
421 			panic("we_write_mbuf: negative len");
422 #ifdef DIAGNOSTIC
423 		if (data != lim)
424 			panic("we_write_mbuf: data != lim");
425 #endif
426 	}
427 	if (leftover) {
428 		savebyte[1] = 0;
429 		bus_space_write_stream_2(memt, memh, buf,
430 		    *(uint16_t *)savebyte);
431 		buf += 2;
432 	}
433 	if (savelen < ETHER_MIN_LEN - ETHER_CRC_LEN) {
434 		bus_space_set_region_2(memt, memh,
435 		    buf, 0, (ETHER_MIN_LEN - ETHER_CRC_LEN - savelen) >> 1);
436 		savelen = ETHER_MIN_LEN - ETHER_CRC_LEN;
437 	}
438 
439  out:
440 	WE_MEM_DISABLE(wsc);
441 
442 	return savelen;
443 }
444 
445 static int
we_ring_copy(struct dp8390_softc * sc,int src,void * dstv,u_short amount)446 we_ring_copy(struct dp8390_softc *sc, int src, void *dstv, u_short amount)
447 {
448 	uint8_t *dst = dstv;
449 	struct we_softc *wsc = (struct we_softc *)sc;
450 	u_short tmp_amount;
451 
452 	/* Does copy wrap to lower addr in ring buffer? */
453 	if (src + amount > sc->mem_end) {
454 		tmp_amount = sc->mem_end - src;
455 
456 		/* Copy amount up to end of NIC memory. */
457 		we_readmem(wsc, src, dst, tmp_amount);
458 
459 		amount -= tmp_amount;
460 		src = sc->mem_ring;
461 		dst += tmp_amount;
462 	}
463 
464 	we_readmem(wsc, src, dst, amount);
465 
466 	return src + amount;
467 }
468 
469 static void
we_read_hdr(struct dp8390_softc * sc,int packet_ptr,struct dp8390_ring * packet_hdrp)470 we_read_hdr(struct dp8390_softc *sc, int packet_ptr,
471     struct dp8390_ring *packet_hdrp)
472 {
473 	struct we_softc *wsc = (struct we_softc *)sc;
474 
475 	we_readmem(wsc, packet_ptr, (uint8_t *)packet_hdrp,
476 	    sizeof(struct dp8390_ring));
477 #if BYTE_ORDER == BIG_ENDIAN
478 	packet_hdrp->count = bswap16(packet_hdrp->count);
479 #endif
480 }
481 
482 static void
we_recv_int(struct dp8390_softc * sc)483 we_recv_int(struct dp8390_softc *sc)
484 {
485 	struct we_softc *wsc = (struct we_softc *)sc;
486 
487 	WE_MEM_ENABLE(wsc);
488 	dp8390_rint(sc);
489 	WE_MEM_DISABLE(wsc);
490 }
491 
492 static void
we_media_init(struct dp8390_softc * sc)493 we_media_init(struct dp8390_softc *sc)
494 {
495 	struct we_softc *wsc = (struct we_softc *)sc;
496 	int defmedia = IFM_ETHER;
497 	uint8_t x;
498 
499 	if (sc->is790) {
500 		x = bus_space_read_1(wsc->sc_asict, wsc->sc_asich, WE790_HWR);
501 		bus_space_write_1(wsc->sc_asict, wsc->sc_asich, WE790_HWR,
502 		    x | WE790_HWR_SWH);
503 		if (bus_space_read_1(wsc->sc_asict, wsc->sc_asich, WE790_GCR) &
504 		    WE790_GCR_GPOUT)
505 			defmedia |= IFM_10_2;
506 		else
507 			defmedia |= IFM_10_5;
508 		bus_space_write_1(wsc->sc_asict, wsc->sc_asich, WE790_HWR,
509 		    x & ~WE790_HWR_SWH);
510 	} else {
511 		x = bus_space_read_1(wsc->sc_asict, wsc->sc_asich, WE_IRR);
512 		if (x & WE_IRR_OUT2)
513 			defmedia |= IFM_10_2;
514 		else
515 			defmedia |= IFM_10_5;
516 	}
517 
518 	ifmedia_init(&sc->sc_media, 0, dp8390_mediachange, dp8390_mediastatus);
519 	ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10_2, 0, NULL);
520 	ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10_5, 0, NULL);
521 	ifmedia_set(&sc->sc_media, defmedia);
522 }
523 
524 static int
we_mediachange(struct dp8390_softc * sc)525 we_mediachange(struct dp8390_softc *sc)
526 {
527 
528 	/*
529 	 * Current media is already set up.  Just reset the interface
530 	 * to let the new value take hold.  The new media will be
531 	 * set up in we_init_card() called via dp8390_init().
532 	 */
533 	dp8390_reset(sc);
534 	return 0;
535 }
536 
537 static void
we_mediastatus(struct dp8390_softc * sc,struct ifmediareq * ifmr)538 we_mediastatus(struct dp8390_softc *sc, struct ifmediareq *ifmr)
539 {
540 	struct ifmedia *ifm = &sc->sc_media;
541 
542 	/*
543 	 * The currently selected media is always the active media.
544 	 */
545 	ifmr->ifm_active = ifm->ifm_cur->ifm_media;
546 }
547 
548 static void
we_init_card(struct dp8390_softc * sc)549 we_init_card(struct dp8390_softc *sc)
550 {
551 	struct we_softc *wsc = (struct we_softc *)sc;
552 	struct ifmedia *ifm = &sc->sc_media;
553 
554 	if (wsc->sc_init_hook)
555 		(*wsc->sc_init_hook)(wsc);
556 
557 	we_set_media(wsc, ifm->ifm_cur->ifm_media);
558 }
559 
560 static void
we_set_media(struct we_softc * wsc,int media)561 we_set_media(struct we_softc *wsc, int media)
562 {
563 	struct dp8390_softc *sc = &wsc->sc_dp8390;
564 	bus_space_tag_t asict = wsc->sc_asict;
565 	bus_space_handle_t asich = wsc->sc_asich;
566 	uint8_t hwr, gcr, irr;
567 
568 	if (sc->is790) {
569 		hwr = bus_space_read_1(asict, asich, WE790_HWR);
570 		bus_space_write_1(asict, asich, WE790_HWR,
571 		    hwr | WE790_HWR_SWH);
572 		gcr = bus_space_read_1(asict, asich, WE790_GCR);
573 		if (IFM_SUBTYPE(media) == IFM_10_2)
574 			gcr |= WE790_GCR_GPOUT;
575 		else
576 			gcr &= ~WE790_GCR_GPOUT;
577 		bus_space_write_1(asict, asich, WE790_GCR,
578 		    gcr | WE790_GCR_LIT);
579 		bus_space_write_1(asict, asich, WE790_HWR,
580 		    hwr & ~WE790_HWR_SWH);
581 		return;
582 	}
583 
584 	irr = bus_space_read_1(wsc->sc_asict, wsc->sc_asich, WE_IRR);
585 	if (IFM_SUBTYPE(media) == IFM_10_2)
586 		irr |= WE_IRR_OUT2;
587 	else
588 		irr &= ~WE_IRR_OUT2;
589 	bus_space_write_1(wsc->sc_asict, wsc->sc_asich, WE_IRR, irr);
590 }
591