if_rue.c revision 226479
154359Sroberto/*-
254359Sroberto * Copyright (c) 2001-2003, Shunsuke Akiyama <akiyama@FreeBSD.org>.
354363Sroberto * Copyright (c) 1997, 1998, 1999, 2000 Bill Paul <wpaul@ee.columbia.edu>.
4330141Sdelphij * All rights reserved.
5330141Sdelphij *
6132454Sroberto * Redistribution and use in source and binary forms, with or without
754359Sroberto * modification, are permitted provided that the following conditions
854359Sroberto * are met:
954359Sroberto * 1. Redistributions of source code must retain the above copyright
1054359Sroberto *    notice, this list of conditions and the following disclaimer.
1154359Sroberto * 2. Redistributions in binary form must reproduce the above copyright
1254359Sroberto *    notice, this list of conditions and the following disclaimer in the
1354359Sroberto *    documentation and/or other materials provided with the distribution.
1454359Sroberto *
1554359Sroberto * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1654359Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17285612Sdelphij * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18285612Sdelphij * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19293650Sglebius * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2054359Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2182505Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22285612Sdelphij * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23285612Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2454359Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25285612Sdelphij * SUCH DAMAGE.
26285612Sdelphij */
2754359Sroberto/*-
2854359Sroberto * Copyright (c) 1997, 1998, 1999, 2000
29298699Sdelphij *	Bill Paul <wpaul@ee.columbia.edu>.  All rights reserved.
30298699Sdelphij *
31298699Sdelphij * Redistribution and use in source and binary forms, with or without
32298699Sdelphij * modification, are permitted provided that the following conditions
33298699Sdelphij * are met:
3454359Sroberto * 1. Redistributions of source code must retain the above copyright
35182007Sroberto *    notice, this list of conditions and the following disclaimer.
36338531Sdelphij * 2. Redistributions in binary form must reproduce the above copyright
37182007Sroberto *    notice, this list of conditions and the following disclaimer in the
38289997Sglebius *    documentation and/or other materials provided with the distribution.
39289997Sglebius * 3. All advertising materials mentioning features or use of this software
40182007Sroberto *    must display the following acknowledgement:
41330141Sdelphij *	This product includes software developed by Bill Paul.
42330141Sdelphij * 4. Neither the name of the author nor the names of any co-contributors
43330141Sdelphij *    may be used to endorse or promote products derived from this software
44330141Sdelphij *    without specific prior written permission.
45330141Sdelphij *
46330141Sdelphij * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
47330141Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48330141Sdelphij * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49285612Sdelphij * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
50182007Sroberto * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
51289997Sglebius * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
52289997Sglebius * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
53289997Sglebius * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
54330141Sdelphij * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
55330141Sdelphij * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
56289997Sglebius * THE POSSIBILITY OF SUCH DAMAGE.
57289997Sglebius */
58289997Sglebius
59289997Sglebius#include <sys/cdefs.h>
60330141Sdelphij__FBSDID("$FreeBSD: head/sys/dev/usb/net/if_rue.c 226479 2011-10-17 19:51:38Z yongari $");
61330141Sdelphij
62289997Sglebius/*
63330141Sdelphij * RealTek RTL8150 USB to fast ethernet controller driver.
64330141Sdelphij * Datasheet is available from
65298699Sdelphij * ftp://ftp.realtek.com.tw/lancard/data_sheet/8150/.
66298699Sdelphij */
67298699Sdelphij
68330141Sdelphij#include <sys/stdint.h>
69298699Sdelphij#include <sys/stddef.h>
70289997Sglebius#include <sys/param.h>
71285612Sdelphij#include <sys/queue.h>
7254359Sroberto#include <sys/types.h>
73285612Sdelphij#include <sys/systm.h>
74285612Sdelphij#include <sys/kernel.h>
75285612Sdelphij#include <sys/bus.h>
76285612Sdelphij#include <sys/module.h>
77285612Sdelphij#include <sys/lock.h>
78285612Sdelphij#include <sys/mutex.h>
79285612Sdelphij#include <sys/condvar.h>
80285612Sdelphij#include <sys/sysctl.h>
81285612Sdelphij#include <sys/sx.h>
82285612Sdelphij#include <sys/unistd.h>
83285612Sdelphij#include <sys/callout.h>
84285612Sdelphij#include <sys/malloc.h>
85285612Sdelphij#include <sys/priv.h>
86285612Sdelphij
87285612Sdelphij#include <dev/usb/usb.h>
88285612Sdelphij#include <dev/usb/usbdi.h>
89285612Sdelphij#include <dev/usb/usbdi_util.h>
90285612Sdelphij#include "usbdevs.h"
91285612Sdelphij
92285612Sdelphij#define	USB_DEBUG_VAR rue_debug
93285612Sdelphij#include <dev/usb/usb_debug.h>
94285612Sdelphij#include <dev/usb/usb_process.h>
95285612Sdelphij
96285612Sdelphij#include <dev/usb/net/usb_ethernet.h>
97285612Sdelphij#include <dev/usb/net/if_ruereg.h>
98285612Sdelphij
99182007Sroberto#ifdef USB_DEBUG
10082505Srobertostatic int rue_debug = 0;
101285612Sdelphij
102285612SdelphijSYSCTL_NODE(_hw_usb, OID_AUTO, rue, CTLFLAG_RW, 0, "USB rue");
103285612SdelphijSYSCTL_INT(_hw_usb_rue, OID_AUTO, debug, CTLFLAG_RW,
104285612Sdelphij    &rue_debug, 0, "Debug level");
10554359Sroberto#endif
106285612Sdelphij
107285612Sdelphij/*
108285612Sdelphij * Various supported device vendors/products.
109285612Sdelphij */
110285612Sdelphij
11154359Srobertostatic const STRUCT_USB_HOST_ID rue_devs[] = {
112285612Sdelphij	{USB_VPI(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAKTX, 0)},
113285612Sdelphij	{USB_VPI(USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_USBKR100, 0)},
114285612Sdelphij	{USB_VPI(USB_VENDOR_OQO, USB_PRODUCT_OQO_ETHER01, 0)},
115285612Sdelphij};
116285612Sdelphij
117285612Sdelphij/* prototypes */
118285612Sdelphij
119285612Sdelphijstatic device_probe_t rue_probe;
12054359Srobertostatic device_attach_t rue_attach;
121285612Sdelphijstatic device_detach_t rue_detach;
122285612Sdelphij
123285612Sdelphijstatic miibus_readreg_t rue_miibus_readreg;
124132454Srobertostatic miibus_writereg_t rue_miibus_writereg;
125132454Srobertostatic miibus_statchg_t rue_miibus_statchg;
12654359Sroberto
12754359Srobertostatic usb_callback_t rue_intr_callback;
128285612Sdelphijstatic usb_callback_t rue_bulk_read_callback;
129285612Sdelphijstatic usb_callback_t rue_bulk_write_callback;
130285612Sdelphij
131285612Sdelphijstatic uether_fn_t rue_attach_post;
132285612Sdelphijstatic uether_fn_t rue_init;
133285612Sdelphijstatic uether_fn_t rue_stop;
134285612Sdelphijstatic uether_fn_t rue_start;
135285612Sdelphijstatic uether_fn_t rue_tick;
13682505Srobertostatic uether_fn_t rue_setmulti;
13782505Srobertostatic uether_fn_t rue_setpromisc;
138285612Sdelphij
13982505Srobertostatic int	rue_read_mem(struct rue_softc *, uint16_t, void *, int);
140132454Srobertostatic int	rue_write_mem(struct rue_softc *, uint16_t, void *, int);
141285612Sdelphijstatic uint8_t	rue_csr_read_1(struct rue_softc *, uint16_t);
14254359Srobertostatic uint16_t	rue_csr_read_2(struct rue_softc *, uint16_t);
14354359Srobertostatic int	rue_csr_write_1(struct rue_softc *, uint16_t, uint8_t);
144132454Srobertostatic int	rue_csr_write_2(struct rue_softc *, uint16_t, uint16_t);
145132454Srobertostatic int	rue_csr_write_4(struct rue_softc *, int, uint32_t);
146182007Sroberto
147309008Sdelphijstatic void	rue_reset(struct rue_softc *);
148285612Sdelphijstatic int	rue_ifmedia_upd(struct ifnet *);
149132454Srobertostatic void	rue_ifmedia_sts(struct ifnet *, struct ifmediareq *);
150285612Sdelphij
151182007Srobertostatic const struct usb_config rue_config[RUE_N_TRANSFER] = {
152132454Sroberto
153182007Sroberto	[RUE_BULK_DT_WR] = {
154285612Sdelphij		.type = UE_BULK,
155182007Sroberto		.endpoint = UE_ADDR_ANY,
156316069Sdelphij		.direction = UE_DIR_OUT,
157132454Sroberto		.bufsize = MCLBYTES,
158132454Sroberto		.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
159132454Sroberto		.callback = rue_bulk_write_callback,
160285612Sdelphij		.timeout = 10000,	/* 10 seconds */
16154359Sroberto	},
162285612Sdelphij
163132454Sroberto	[RUE_BULK_DT_RD] = {
164285612Sdelphij		.type = UE_BULK,
165285612Sdelphij		.endpoint = UE_ADDR_ANY,
166285612Sdelphij		.direction = UE_DIR_IN,
167132454Sroberto		.bufsize = (MCLBYTES + 4),
168132454Sroberto		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
169132454Sroberto		.callback = rue_bulk_read_callback,
170285612Sdelphij		.timeout = 0,	/* no timeout */
171132454Sroberto	},
172285612Sdelphij
17354359Sroberto	[RUE_INTR_DT_RD] = {
174294569Sdelphij		.type = UE_INTERRUPT,
175301256Sdelphij		.endpoint = UE_ADDR_ANY,
176294569Sdelphij		.direction = UE_DIR_IN,
177294569Sdelphij		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
178294569Sdelphij		.bufsize = 0,	/* use wMaxPacketSize */
179294569Sdelphij		.callback = rue_intr_callback,
180294569Sdelphij	},
181294569Sdelphij};
182294569Sdelphij
183301256Sdelphijstatic device_method_t rue_methods[] = {
184294569Sdelphij	/* Device interface */
185294569Sdelphij	DEVMETHOD(device_probe, rue_probe),
186294569Sdelphij	DEVMETHOD(device_attach, rue_attach),
187294569Sdelphij	DEVMETHOD(device_detach, rue_detach),
188298699Sdelphij
189298699Sdelphij	/* Bus interface */
190298699Sdelphij	DEVMETHOD(bus_print_child, bus_generic_print_child),
191330141Sdelphij
192285612Sdelphij	/* MII interface */
193285612Sdelphij	DEVMETHOD(miibus_readreg, rue_miibus_readreg),
194285612Sdelphij	DEVMETHOD(miibus_writereg, rue_miibus_writereg),
195285612Sdelphij	DEVMETHOD(miibus_statchg, rue_miibus_statchg),
196285612Sdelphij
197285612Sdelphij	{0, 0}
198285612Sdelphij};
199285612Sdelphij
200285612Sdelphijstatic driver_t rue_driver = {
201285612Sdelphij	.name = "rue",
202285612Sdelphij	.methods = rue_methods,
203285612Sdelphij	.size = sizeof(struct rue_softc),
204285612Sdelphij};
205285612Sdelphij
206285612Sdelphijstatic devclass_t rue_devclass;
207285612Sdelphij
208285612SdelphijDRIVER_MODULE(rue, uhub, rue_driver, rue_devclass, NULL, 0);
209285612SdelphijDRIVER_MODULE(miibus, rue, miibus_driver, miibus_devclass, 0, 0);
21054359SrobertoMODULE_DEPEND(rue, uether, 1, 1, 1);
211293650SglebiusMODULE_DEPEND(rue, usb, 1, 1, 1);
212293650SglebiusMODULE_DEPEND(rue, ether, 1, 1, 1);
213293650SglebiusMODULE_DEPEND(rue, miibus, 1, 1, 1);
214285612SdelphijMODULE_VERSION(rue, 1);
215293650Sglebius
216293650Sglebiusstatic const struct usb_ether_methods rue_ue_methods = {
217293650Sglebius	.ue_attach_post = rue_attach_post,
218293650Sglebius	.ue_start = rue_start,
219285612Sdelphij	.ue_init = rue_init,
220285612Sdelphij	.ue_stop = rue_stop,
221182007Sroberto	.ue_tick = rue_tick,
222285612Sdelphij	.ue_setmulti = rue_setmulti,
223285612Sdelphij	.ue_setpromisc = rue_setpromisc,
224285612Sdelphij	.ue_mii_upd = rue_ifmedia_upd,
225285612Sdelphij	.ue_mii_sts = rue_ifmedia_sts,
226285612Sdelphij};
227285612Sdelphij
228285612Sdelphij#define	RUE_SETBIT(sc, reg, x) \
229285612Sdelphij	rue_csr_write_1(sc, reg, rue_csr_read_1(sc, reg) | (x))
230285612Sdelphij
231285612Sdelphij#define	RUE_CLRBIT(sc, reg, x) \
232285612Sdelphij	rue_csr_write_1(sc, reg, rue_csr_read_1(sc, reg) & ~(x))
233285612Sdelphij
234293650Sglebiusstatic int
235293650Sglebiusrue_read_mem(struct rue_softc *sc, uint16_t addr, void *buf, int len)
236293650Sglebius{
237285612Sdelphij	struct usb_device_request req;
238285612Sdelphij
239285612Sdelphij	req.bmRequestType = UT_READ_VENDOR_DEVICE;
240285612Sdelphij	req.bRequest = UR_SET_ADDRESS;
241285612Sdelphij	USETW(req.wValue, addr);
242285612Sdelphij	USETW(req.wIndex, 0);
243285612Sdelphij	USETW(req.wLength, len);
244285612Sdelphij
245293650Sglebius	return (uether_do_request(&sc->sc_ue, &req, buf, 1000));
246289997Sglebius}
247289997Sglebius
248289997Sglebiusstatic int
249293650Sglebiusrue_write_mem(struct rue_softc *sc, uint16_t addr, void *buf, int len)
250293650Sglebius{
251293650Sglebius	struct usb_device_request req;
252293650Sglebius
253293650Sglebius	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
254293650Sglebius	req.bRequest = UR_SET_ADDRESS;
255293650Sglebius	USETW(req.wValue, addr);
256293650Sglebius	USETW(req.wIndex, 0);
257285612Sdelphij	USETW(req.wLength, len);
258293650Sglebius
259293650Sglebius	return (uether_do_request(&sc->sc_ue, &req, buf, 1000));
260293650Sglebius}
261293650Sglebius
262293650Sglebiusstatic uint8_t
263293650Sglebiusrue_csr_read_1(struct rue_softc *sc, uint16_t reg)
264293650Sglebius{
265293650Sglebius	uint8_t val;
266293650Sglebius
267293650Sglebius	rue_read_mem(sc, reg, &val, 1);
268293650Sglebius	return (val);
269289997Sglebius}
270293650Sglebius
271330141Sdelphijstatic uint16_t
272289997Sglebiusrue_csr_read_2(struct rue_softc *sc, uint16_t reg)
273293650Sglebius{
274293650Sglebius	uint8_t val[2];
275338531Sdelphij
276298699Sdelphij	rue_read_mem(sc, reg, &val, 2);
277298699Sdelphij	return (UGETW(val));
278330141Sdelphij}
279298699Sdelphij
280298699Sdelphijstatic int
281298699Sdelphijrue_csr_write_1(struct rue_softc *sc, uint16_t reg, uint8_t val)
282298699Sdelphij{
283298699Sdelphij	return (rue_write_mem(sc, reg, &val, 1));
284298699Sdelphij}
285309008Sdelphij
286301256Sdelphijstatic int
287301256Sdelphijrue_csr_write_2(struct rue_softc *sc, uint16_t reg, uint16_t val)
288301256Sdelphij{
289301256Sdelphij	uint8_t temp[2];
290301256Sdelphij
291298699Sdelphij	USETW(temp, val);
292298699Sdelphij	return (rue_write_mem(sc, reg, &temp, 2));
293298699Sdelphij}
294298699Sdelphij
295298699Sdelphijstatic int
296298699Sdelphijrue_csr_write_4(struct rue_softc *sc, int reg, uint32_t val)
297298699Sdelphij{
298298699Sdelphij	uint8_t temp[4];
299298699Sdelphij
300298699Sdelphij	USETDW(temp, val);
301298699Sdelphij	return (rue_write_mem(sc, reg, &temp, 4));
302298699Sdelphij}
303298699Sdelphij
304298699Sdelphijstatic int
305298699Sdelphijrue_miibus_readreg(device_t dev, int phy, int reg)
306298699Sdelphij{
307298699Sdelphij	struct rue_softc *sc = device_get_softc(dev);
308298699Sdelphij	uint16_t rval;
309298699Sdelphij	uint16_t ruereg;
310298699Sdelphij	int locked;
311298699Sdelphij
312298699Sdelphij	if (phy != 0)		/* RTL8150 supports PHY == 0, only */
313298699Sdelphij		return (0);
314298699Sdelphij
315301256Sdelphij	locked = mtx_owned(&sc->sc_mtx);
316298699Sdelphij	if (!locked)
317298699Sdelphij		RUE_LOCK(sc);
318338531Sdelphij
319298699Sdelphij	switch (reg) {
320298699Sdelphij	case MII_BMCR:
321298699Sdelphij		ruereg = RUE_BMCR;
322298699Sdelphij		break;
323298699Sdelphij	case MII_BMSR:
324301256Sdelphij		ruereg = RUE_BMSR;
325298699Sdelphij		break;
326298699Sdelphij	case MII_ANAR:
327338531Sdelphij		ruereg = RUE_ANAR;
328338531Sdelphij		break;
329338531Sdelphij	case MII_ANER:
330338531Sdelphij		ruereg = RUE_AER;
331338531Sdelphij		break;
332298699Sdelphij	case MII_ANLPAR:
333338531Sdelphij		ruereg = RUE_ANLP;
334301256Sdelphij		break;
335298699Sdelphij	case MII_PHYIDR1:
336301256Sdelphij	case MII_PHYIDR2:
337301256Sdelphij		rval = 0;
338301256Sdelphij		goto done;
339301256Sdelphij	default:
340301256Sdelphij		if (RUE_REG_MIN <= reg && reg <= RUE_REG_MAX) {
341301256Sdelphij			rval = rue_csr_read_1(sc, reg);
342301256Sdelphij			goto done;
343301256Sdelphij		}
344301256Sdelphij		device_printf(sc->sc_ue.ue_dev, "bad phy register\n");
345309008Sdelphij		rval = 0;
346301256Sdelphij		goto done;
347301256Sdelphij	}
348301256Sdelphij
349301256Sdelphij	rval = rue_csr_read_2(sc, ruereg);
350298699Sdelphijdone:
351301256Sdelphij	if (!locked)
352301256Sdelphij		RUE_UNLOCK(sc);
353301256Sdelphij	return (rval);
354301256Sdelphij}
355301256Sdelphij
356298699Sdelphijstatic int
357298699Sdelphijrue_miibus_writereg(device_t dev, int phy, int reg, int data)
358298699Sdelphij{
35954359Sroberto	struct rue_softc *sc = device_get_softc(dev);
360285612Sdelphij	uint16_t ruereg;
36154359Sroberto	int locked;
36254359Sroberto
36354359Sroberto	if (phy != 0)		/* RTL8150 supports PHY == 0, only */
36454359Sroberto		return (0);
36554359Sroberto
36654359Sroberto	locked = mtx_owned(&sc->sc_mtx);
367285612Sdelphij	if (!locked)
36854359Sroberto		RUE_LOCK(sc);
369132454Sroberto
370132454Sroberto	switch (reg) {
371132454Sroberto	case MII_BMCR:
372132454Sroberto		ruereg = RUE_BMCR;
373132454Sroberto		break;
374132454Sroberto	case MII_BMSR:
37554359Sroberto		ruereg = RUE_BMSR;
376182007Sroberto		break;
377182007Sroberto	case MII_ANAR:
378338531Sdelphij		ruereg = RUE_ANAR;
379338531Sdelphij		break;
380338531Sdelphij	case MII_ANER:
381338531Sdelphij		ruereg = RUE_AER;
382338531Sdelphij		break;
383338531Sdelphij	case MII_ANLPAR:
384338531Sdelphij		ruereg = RUE_ANLP;
385182007Sroberto		break;
386182007Sroberto	case MII_PHYIDR1:
387182007Sroberto	case MII_PHYIDR2:
388132454Sroberto		goto done;
389182007Sroberto	default:
390285612Sdelphij		if (RUE_REG_MIN <= reg && reg <= RUE_REG_MAX) {
391285612Sdelphij			rue_csr_write_1(sc, reg, data);
392182007Sroberto			goto done;
393182007Sroberto		}
394182007Sroberto		device_printf(sc->sc_ue.ue_dev, " bad phy register\n");
39554359Sroberto		goto done;
396182007Sroberto	}
397182007Sroberto	rue_csr_write_2(sc, ruereg, data);
398182007Srobertodone:
399182007Sroberto	if (!locked)
400182007Sroberto		RUE_UNLOCK(sc);
401285612Sdelphij	return (0);
402182007Sroberto}
403285612Sdelphij
404285612Sdelphijstatic void
405285612Sdelphijrue_miibus_statchg(device_t dev)
406285612Sdelphij{
407285612Sdelphij	/*
408182007Sroberto	 * When the code below is enabled the card starts doing weird
409182007Sroberto	 * things after link going from UP to DOWN and back UP.
410182007Sroberto	 *
411182007Sroberto	 * Looks like some of register writes below messes up PHY
412182007Sroberto	 * interface.
413182007Sroberto	 *
414182007Sroberto	 * No visible regressions were found after commenting this code
415289997Sglebius	 * out, so that disable it for good.
416289997Sglebius	 */
417316069Sdelphij#if 0
418182007Sroberto	struct rue_softc *sc = device_get_softc(dev);
419182007Sroberto	struct mii_data *mii = GET_MII(sc);
420182007Sroberto	uint16_t bmcr;
421182007Sroberto	int locked;
422182007Sroberto
423182007Sroberto	locked = mtx_owned(&sc->sc_mtx);
424182007Sroberto	if (!locked)
42582505Sroberto		RUE_LOCK(sc);
426182007Sroberto
427285612Sdelphij	RUE_CLRBIT(sc, RUE_CR, (RUE_CR_RE | RUE_CR_TE));
428285612Sdelphij
429285612Sdelphij	bmcr = rue_csr_read_2(sc, RUE_BMCR);
430285612Sdelphij
431285612Sdelphij	if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX)
432285612Sdelphij		bmcr |= RUE_BMCR_SPD_SET;
433285612Sdelphij	else
434285612Sdelphij		bmcr &= ~RUE_BMCR_SPD_SET;
435285612Sdelphij
436285612Sdelphij	if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX)
437285612Sdelphij		bmcr |= RUE_BMCR_DUPLEX;
438285612Sdelphij	else
439285612Sdelphij		bmcr &= ~RUE_BMCR_DUPLEX;
440289997Sglebius
441289997Sglebius	rue_csr_write_2(sc, RUE_BMCR, bmcr);
442293650Sglebius
443285612Sdelphij	RUE_SETBIT(sc, RUE_CR, (RUE_CR_RE | RUE_CR_TE));
444285612Sdelphij
445285612Sdelphij	if (!locked)
446285612Sdelphij		RUE_UNLOCK(sc);
447285612Sdelphij#endif
448285612Sdelphij}
449182007Sroberto
450285612Sdelphijstatic void
451182007Srobertorue_setpromisc(struct usb_ether *ue)
452182007Sroberto{
453182007Sroberto	struct rue_softc *sc = uether_getsc(ue);
454182007Sroberto	struct ifnet *ifp = uether_getifp(ue);
455182007Sroberto
456132454Sroberto	RUE_LOCK_ASSERT(sc, MA_OWNED);
457182007Sroberto
458182007Sroberto	/* If we want promiscuous mode, set the allframes bit. */
459285612Sdelphij	if (ifp->if_flags & IFF_PROMISC)
460132454Sroberto		RUE_SETBIT(sc, RUE_RCR, RUE_RCR_AAP);
461182007Sroberto	else
462182007Sroberto		RUE_CLRBIT(sc, RUE_RCR, RUE_RCR_AAP);
463285612Sdelphij}
464182007Sroberto
465182007Sroberto/*
46682505Sroberto * Program the 64-bit multicast hash filter.
467182007Sroberto */
468182007Srobertostatic void
469285612Sdelphijrue_setmulti(struct usb_ether *ue)
470285612Sdelphij{
471182007Sroberto	struct rue_softc *sc = uether_getsc(ue);
472285612Sdelphij	struct ifnet *ifp = uether_getifp(ue);
473182007Sroberto	uint16_t rxcfg;
474285612Sdelphij	int h = 0;
475285612Sdelphij	uint32_t hashes[2] = { 0, 0 };
476182007Sroberto	struct ifmultiaddr *ifma;
477289997Sglebius	int mcnt = 0;
478289997Sglebius
479285612Sdelphij	RUE_LOCK_ASSERT(sc, MA_OWNED);
480182007Sroberto
481182007Sroberto	rxcfg = rue_csr_read_2(sc, RUE_RCR);
482182007Sroberto
483285612Sdelphij	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
484285612Sdelphij		rxcfg |= (RUE_RCR_AAM | RUE_RCR_AAP);
485285612Sdelphij		rxcfg &= ~RUE_RCR_AM;
486285612Sdelphij		rue_csr_write_2(sc, RUE_RCR, rxcfg);
487285612Sdelphij		rue_csr_write_4(sc, RUE_MAR0, 0xFFFFFFFF);
488182007Sroberto		rue_csr_write_4(sc, RUE_MAR4, 0xFFFFFFFF);
489285612Sdelphij		return;
490285612Sdelphij	}
491182007Sroberto
492289997Sglebius	/* first, zot all the existing hash bits */
493289997Sglebius	rue_csr_write_4(sc, RUE_MAR0, 0);
494289997Sglebius	rue_csr_write_4(sc, RUE_MAR4, 0);
495285612Sdelphij
496182007Sroberto	/* now program new ones */
497182007Sroberto	if_maddr_rlock(ifp);
498132454Sroberto	TAILQ_FOREACH (ifma, &ifp->if_multiaddrs, ifma_link)
499285612Sdelphij	{
500285612Sdelphij		if (ifma->ifma_addr->sa_family != AF_LINK)
501285612Sdelphij			continue;
502285612Sdelphij		h = ether_crc32_be(LLADDR((struct sockaddr_dl *)
503285612Sdelphij		    ifma->ifma_addr), ETHER_ADDR_LEN) >> 26;
504285612Sdelphij		if (h < 32)
505285612Sdelphij			hashes[0] |= (1 << h);
506132454Sroberto		else
507285612Sdelphij			hashes[1] |= (1 << (h - 32));
508285612Sdelphij		mcnt++;
509285612Sdelphij	}
510285612Sdelphij	if_maddr_runlock(ifp);
511182007Sroberto
51282505Sroberto	if (mcnt)
51382505Sroberto		rxcfg |= RUE_RCR_AM;
51482505Sroberto	else
515289997Sglebius		rxcfg &= ~RUE_RCR_AM;
516289997Sglebius
517289997Sglebius	rxcfg &= ~(RUE_RCR_AAM | RUE_RCR_AAP);
518285612Sdelphij
519285612Sdelphij	rue_csr_write_2(sc, RUE_RCR, rxcfg);
520285612Sdelphij	rue_csr_write_4(sc, RUE_MAR0, hashes[0]);
521285612Sdelphij	rue_csr_write_4(sc, RUE_MAR4, hashes[1]);
522285612Sdelphij}
52382505Sroberto
524182007Srobertostatic void
525182007Srobertorue_reset(struct rue_softc *sc)
526132454Sroberto{
52754359Sroberto	int i;
52854359Sroberto
529182007Sroberto	rue_csr_write_1(sc, RUE_CR, RUE_CR_SOFT_RST);
530182007Sroberto
531182007Sroberto	for (i = 0; i != RUE_TIMEOUT; i++) {
53254359Sroberto		if (uether_pause(&sc->sc_ue, hz / 1000))
533182007Sroberto			break;
534182007Sroberto		if (!(rue_csr_read_1(sc, RUE_CR) & RUE_CR_SOFT_RST))
535182007Sroberto			break;
536132454Sroberto	}
537285612Sdelphij	if (i == RUE_TIMEOUT)
538285612Sdelphij		device_printf(sc->sc_ue.ue_dev, "reset never completed\n");
539285612Sdelphij
540285612Sdelphij	uether_pause(&sc->sc_ue, hz / 100);
541132454Sroberto}
542132454Sroberto
54354359Srobertostatic void
54454359Srobertorue_attach_post(struct usb_ether *ue)
54554359Sroberto{
546285612Sdelphij	struct rue_softc *sc = uether_getsc(ue);
547285612Sdelphij
54854359Sroberto	/* reset the adapter */
54954359Sroberto	rue_reset(sc);
550285612Sdelphij
55154359Sroberto	/* get station address from the EEPROM */
552182007Sroberto	rue_read_mem(sc, RUE_EEPROM_IDR0, ue->ue_eaddr, ETHER_ADDR_LEN);
553182007Sroberto}
554132454Sroberto
555293650Sglebius/*
556293650Sglebius * Probe for a RTL8150 chip.
55754359Sroberto */
55854359Srobertostatic int
559182007Srobertorue_probe(device_t dev)
560293650Sglebius{
561293650Sglebius	struct usb_attach_arg *uaa = device_get_ivars(dev);
562293650Sglebius
563293650Sglebius	if (uaa->usb_mode != USB_MODE_HOST)
564293650Sglebius		return (ENXIO);
565293650Sglebius	if (uaa->info.bConfigIndex != RUE_CONFIG_IDX)
566293650Sglebius		return (ENXIO);
567293650Sglebius	if (uaa->info.bIfaceIndex != RUE_IFACE_IDX)
568293650Sglebius		return (ENXIO);
569293650Sglebius
570293650Sglebius	return (usbd_lookup_id_by_uaa(rue_devs, sizeof(rue_devs), uaa));
571293650Sglebius}
572293650Sglebius
573293650Sglebius/*
574293650Sglebius * Attach the interface. Allocate softc structures, do ifmedia
575293650Sglebius * setup and ethernet/BPF attach.
576293650Sglebius */
577293650Sglebiusstatic int
578293650Sglebiusrue_attach(device_t dev)
579293650Sglebius{
580293650Sglebius	struct usb_attach_arg *uaa = device_get_ivars(dev);
581293650Sglebius	struct rue_softc *sc = device_get_softc(dev);
582293650Sglebius	struct usb_ether *ue = &sc->sc_ue;
583293650Sglebius	uint8_t iface_index;
584293650Sglebius	int error;
58554359Sroberto
586285612Sdelphij	device_set_usb_desc(dev);
58754359Sroberto	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
58854359Sroberto
58954359Sroberto	iface_index = RUE_IFACE_IDX;
59054359Sroberto	error = usbd_transfer_setup(uaa->device, &iface_index,
59154359Sroberto	    sc->sc_xfer, rue_config, RUE_N_TRANSFER,
59254359Sroberto	    sc, &sc->sc_mtx);
593132454Sroberto	if (error) {
594132454Sroberto		device_printf(dev, "allocating USB transfers failed\n");
595285612Sdelphij		goto detach;
596285612Sdelphij	}
597285612Sdelphij
598285612Sdelphij	ue->ue_sc = sc;
599330141Sdelphij	ue->ue_dev = dev;
600285612Sdelphij	ue->ue_udev = uaa->device;
601293650Sglebius	ue->ue_mtx = &sc->sc_mtx;
602293650Sglebius	ue->ue_methods = &rue_ue_methods;
603293650Sglebius
604132454Sroberto	error = uether_ifattach(ue);
605132454Sroberto	if (error) {
606330141Sdelphij		device_printf(dev, "could not attach interface\n");
607330141Sdelphij		goto detach;
608285612Sdelphij	}
609285612Sdelphij	return (0);			/* success */
610285612Sdelphij
611293650Sglebiusdetach:
612132454Sroberto	rue_detach(dev);
613293650Sglebius	return (ENXIO);			/* failure */
614182007Sroberto}
615182007Sroberto
616132454Srobertostatic int
617285612Sdelphijrue_detach(device_t dev)
618285612Sdelphij{
619285612Sdelphij	struct rue_softc *sc = device_get_softc(dev);
620132454Sroberto	struct usb_ether *ue = &sc->sc_ue;
621132454Sroberto
622285612Sdelphij	usbd_transfer_unsetup(sc->sc_xfer, RUE_N_TRANSFER);
623285612Sdelphij	uether_ifdetach(ue);
624285612Sdelphij	mtx_destroy(&sc->sc_mtx);
625285612Sdelphij
626285612Sdelphij	return (0);
62754359Sroberto}
62854359Sroberto
629330141Sdelphijstatic void
630330141Sdelphijrue_intr_callback(struct usb_xfer *xfer, usb_error_t error)
631330141Sdelphij{
632330141Sdelphij	struct rue_softc *sc = usbd_xfer_softc(xfer);
633330141Sdelphij	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
634330141Sdelphij	struct rue_intrpkt pkt;
635330141Sdelphij	struct usb_page_cache *pc;
63682505Sroberto	int actlen;
63782505Sroberto
638285612Sdelphij	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
639285612Sdelphij
64054359Sroberto	switch (USB_GET_STATE(xfer)) {
641132454Sroberto	case USB_ST_TRANSFERRED:
642132454Sroberto
643132454Sroberto		if (ifp && (ifp->if_drv_flags & IFF_DRV_RUNNING) &&
644132454Sroberto		    actlen >= sizeof(pkt)) {
645132454Sroberto
646285612Sdelphij			pc = usbd_xfer_get_frame(xfer, 0);
647132454Sroberto			usbd_copy_out(pc, 0, &pkt, sizeof(pkt));
648132454Sroberto
649132454Sroberto			ifp->if_ierrors += pkt.rue_rxlost_cnt;
650330141Sdelphij			ifp->if_ierrors += pkt.rue_crcerr_cnt;
651330141Sdelphij			ifp->if_collisions += pkt.rue_col_cnt;
652330141Sdelphij		}
653293650Sglebius		/* FALLTHROUGH */
654182007Sroberto	case USB_ST_SETUP:
655182007Srobertotr_setup:
656132454Sroberto		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
657182007Sroberto		usbd_transfer_submit(xfer);
658338531Sdelphij		return;
659330141Sdelphij
660330141Sdelphij	default:			/* Error */
661330141Sdelphij		if (error != USB_ERR_CANCELLED) {
662330141Sdelphij			/* try to clear stall first */
663330141Sdelphij			usbd_xfer_set_stall(xfer);
664330141Sdelphij			goto tr_setup;
665330141Sdelphij		}
666330141Sdelphij		return;
667301256Sdelphij	}
668301256Sdelphij}
669285612Sdelphij
670330141Sdelphijstatic void
671285612Sdelphijrue_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
672285612Sdelphij{
673285612Sdelphij	struct rue_softc *sc = usbd_xfer_softc(xfer);
674132454Sroberto	struct usb_ether *ue = &sc->sc_ue;
675285612Sdelphij	struct ifnet *ifp = uether_getifp(ue);
676330141Sdelphij	struct usb_page_cache *pc;
677132454Sroberto	uint16_t status;
67882505Sroberto	int actlen;
679132454Sroberto
68056749Sroberto	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
68156749Sroberto
68254359Sroberto	switch (USB_GET_STATE(xfer)) {
68354359Sroberto	case USB_ST_TRANSFERRED:
684132454Sroberto
685132454Sroberto		if (actlen < 4) {
686330141Sdelphij			ifp->if_ierrors++;
687132454Sroberto			goto tr_setup;
68882505Sroberto		}
689132454Sroberto		pc = usbd_xfer_get_frame(xfer, 0);
69054359Sroberto		usbd_copy_out(pc, actlen - 4, &status, sizeof(status));
69154359Sroberto		actlen -= 4;
69254359Sroberto
693132454Sroberto		/* check recieve packet was valid or not */
694330141Sdelphij		status = le16toh(status);
695132454Sroberto		if ((status & RUE_RXSTAT_VALID) == 0) {
696285612Sdelphij			ifp->if_ierrors++;
697132454Sroberto			goto tr_setup;
698285612Sdelphij		}
699285612Sdelphij		uether_rxbuf(ue, pc, 0, actlen);
700285612Sdelphij		/* FALLTHROUGH */
701285612Sdelphij	case USB_ST_SETUP:
702285612Sdelphijtr_setup:
703285612Sdelphij		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
704285612Sdelphij		usbd_transfer_submit(xfer);
705330141Sdelphij		uether_rxflush(ue);
706285612Sdelphij		return;
707285612Sdelphij
708285612Sdelphij	default:			/* Error */
70982505Sroberto		DPRINTF("bulk read error, %s\n",
710285612Sdelphij		    usbd_errstr(error));
711132454Sroberto
712330141Sdelphij		if (error != USB_ERR_CANCELLED) {
713330141Sdelphij			/* try to clear stall first */
714330141Sdelphij			usbd_xfer_set_stall(xfer);
715330141Sdelphij			goto tr_setup;
716330141Sdelphij		}
717330141Sdelphij		return;
718330141Sdelphij	}
719330141Sdelphij}
720330141Sdelphij
721330141Sdelphijstatic void
722330141Sdelphijrue_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
723330141Sdelphij{
724132454Sroberto	struct rue_softc *sc = usbd_xfer_softc(xfer);
725285612Sdelphij	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
726132454Sroberto	struct usb_page_cache *pc;
727182007Sroberto	struct mbuf *m;
728285612Sdelphij	int temp_len;
729289997Sglebius
730289997Sglebius	switch (USB_GET_STATE(xfer)) {
731285612Sdelphij	case USB_ST_TRANSFERRED:
732132454Sroberto		DPRINTFN(11, "transfer complete\n");
733330141Sdelphij		ifp->if_opackets++;
734285612Sdelphij
735132454Sroberto		/* FALLTHROUGH */
736132454Sroberto	case USB_ST_SETUP:
73754359Srobertotr_setup:
73854359Sroberto		if ((sc->sc_flags & RUE_FLAG_LINK) == 0) {
739132454Sroberto			/*
740132454Sroberto			 * don't send anything if there is no link !
741132454Sroberto			 */
742132454Sroberto			return;
74354359Sroberto		}
74482505Sroberto		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
745182007Sroberto
746132454Sroberto		if (m == NULL)
747132454Sroberto			return;
748330141Sdelphij		if (m->m_pkthdr.len > MCLBYTES)
749132454Sroberto			m->m_pkthdr.len = MCLBYTES;
750338531Sdelphij		temp_len = m->m_pkthdr.len;
751132454Sroberto
75282505Sroberto		pc = usbd_xfer_get_frame(xfer, 0);
75354359Sroberto		usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len);
75454359Sroberto
75582505Sroberto		/*
75682505Sroberto		 * This is an undocumented behavior.
757182007Sroberto		 * RTL8150 chip doesn't send frame length smaller than
758182007Sroberto		 * RUE_MIN_FRAMELEN (60) byte packet.
759182007Sroberto		 */
760285612Sdelphij		if (temp_len < RUE_MIN_FRAMELEN) {
761285612Sdelphij			usbd_frame_zero(pc, temp_len,
762285612Sdelphij			    RUE_MIN_FRAMELEN - temp_len);
763285612Sdelphij			temp_len = RUE_MIN_FRAMELEN;
764285612Sdelphij		}
765330141Sdelphij		usbd_xfer_set_frame_len(xfer, 0, temp_len);
766330141Sdelphij
767330141Sdelphij		/*
768330141Sdelphij		 * if there's a BPF listener, bounce a copy
769330141Sdelphij		 * of this frame to him:
770330141Sdelphij		 */
771330141Sdelphij		BPF_MTAP(ifp, m);
772330141Sdelphij
773330141Sdelphij		m_freem(m);
774330141Sdelphij
77554359Sroberto		usbd_transfer_submit(xfer);
776298699Sdelphij
77754359Sroberto		return;
778132454Sroberto
779132454Sroberto	default:			/* Error */
780285612Sdelphij		DPRINTFN(11, "transfer error, %s\n",
781285612Sdelphij		    usbd_errstr(error));
782285612Sdelphij
783285612Sdelphij		ifp->if_oerrors++;
784285612Sdelphij
78582505Sroberto		if (error != USB_ERR_CANCELLED) {
786285612Sdelphij			/* try to clear stall first */
787330141Sdelphij			usbd_xfer_set_stall(xfer);
78854359Sroberto			goto tr_setup;
789285612Sdelphij		}
79054359Sroberto		return;
791330141Sdelphij	}
792330141Sdelphij}
793330141Sdelphij
794330141Sdelphijstatic void
795285612Sdelphijrue_tick(struct usb_ether *ue)
79682505Sroberto{
79782505Sroberto	struct rue_softc *sc = uether_getsc(ue);
79854359Sroberto	struct mii_data *mii = GET_MII(sc);
799285612Sdelphij
800285612Sdelphij	RUE_LOCK_ASSERT(sc, MA_OWNED);
801285612Sdelphij
802289997Sglebius	mii_tick(mii);
803289997Sglebius	if ((sc->sc_flags & RUE_FLAG_LINK) == 0
804289997Sglebius	    && mii->mii_media_status & IFM_ACTIVE &&
805330141Sdelphij	    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
80682505Sroberto		sc->sc_flags |= RUE_FLAG_LINK;
807285612Sdelphij		rue_start(ue);
80882505Sroberto	}
809285612Sdelphij}
810285612Sdelphij
811285612Sdelphijstatic void
812285612Sdelphijrue_start(struct usb_ether *ue)
813285612Sdelphij{
814285612Sdelphij	struct rue_softc *sc = uether_getsc(ue);
815289997Sglebius
816289997Sglebius	/*
817285612Sdelphij	 * start the USB transfers, if not already started:
818285612Sdelphij	 */
819289997Sglebius	usbd_transfer_start(sc->sc_xfer[RUE_INTR_DT_RD]);
820289997Sglebius	usbd_transfer_start(sc->sc_xfer[RUE_BULK_DT_RD]);
821289997Sglebius	usbd_transfer_start(sc->sc_xfer[RUE_BULK_DT_WR]);
822330141Sdelphij}
823285612Sdelphij
824285612Sdelphijstatic void
825285612Sdelphijrue_init(struct usb_ether *ue)
826285612Sdelphij{
827285612Sdelphij	struct rue_softc *sc = uether_getsc(ue);
828285612Sdelphij	struct ifnet *ifp = uether_getifp(ue);
829285612Sdelphij
830330141Sdelphij	RUE_LOCK_ASSERT(sc, MA_OWNED);
831285612Sdelphij
832285612Sdelphij	/*
833285612Sdelphij	 * Cancel pending I/O
834285612Sdelphij	 */
835285612Sdelphij	rue_reset(sc);
836285612Sdelphij
837285612Sdelphij	/* Set MAC address */
838285612Sdelphij	rue_write_mem(sc, RUE_IDR0, IF_LLADDR(ifp), ETHER_ADDR_LEN);
83982505Sroberto
84054359Sroberto	rue_stop(ue);
841285612Sdelphij
842281230Sdelphij	/*
843281230Sdelphij	 * Set the initial TX and RX configuration.
844281230Sdelphij	 */
845281230Sdelphij	rue_csr_write_1(sc, RUE_TCR, RUE_TCR_CONFIG);
846330141Sdelphij	rue_csr_write_2(sc, RUE_RCR, RUE_RCR_CONFIG|RUE_RCR_AB);
847281230Sdelphij
848281230Sdelphij	/* Load the multicast filter */
849281230Sdelphij	rue_setpromisc(ue);
85054359Sroberto	/* Load the multicast filter. */
85154359Sroberto	rue_setmulti(ue);
852330141Sdelphij
853330141Sdelphij	/* Enable RX and TX */
854338531Sdelphij	rue_csr_write_1(sc, RUE_CR, (RUE_CR_TE | RUE_CR_RE | RUE_CR_EP3CLREN));
855330141Sdelphij
856330141Sdelphij	usbd_xfer_set_stall(sc->sc_xfer[RUE_BULK_DT_WR]);
857330141Sdelphij
858330141Sdelphij	ifp->if_drv_flags |= IFF_DRV_RUNNING;
859330141Sdelphij	rue_start(ue);
860330141Sdelphij}
861330141Sdelphij
862330141Sdelphij/*
863330141Sdelphij * Set media options.
864285612Sdelphij */
865285612Sdelphijstatic int
866330141Sdelphijrue_ifmedia_upd(struct ifnet *ifp)
867285612Sdelphij{
868285612Sdelphij	struct rue_softc *sc = ifp->if_softc;
869285612Sdelphij	struct mii_data *mii = GET_MII(sc);
870285612Sdelphij	struct mii_softc *miisc;
871285612Sdelphij
872285612Sdelphij	RUE_LOCK_ASSERT(sc, MA_OWNED);
873285612Sdelphij
874285612Sdelphij        sc->sc_flags &= ~RUE_FLAG_LINK;
875285612Sdelphij	LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
876285612Sdelphij		PHY_RESET(miisc);
877285612Sdelphij	mii_mediachg(mii);
878285612Sdelphij	return (0);
879285612Sdelphij}
880289997Sglebius
881289997Sglebius/*
882289997Sglebius * Report current media status.
883330141Sdelphij */
884285612Sdelphijstatic void
885285612Sdelphijrue_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
886330141Sdelphij{
887330141Sdelphij	struct rue_softc *sc = ifp->if_softc;
888330141Sdelphij	struct mii_data *mii = GET_MII(sc);
889285612Sdelphij
890285612Sdelphij	RUE_LOCK(sc);
891285612Sdelphij	mii_pollstat(mii);
892285612Sdelphij	ifmr->ifm_active = mii->mii_media_active;
893285612Sdelphij	ifmr->ifm_status = mii->mii_media_status;
894285612Sdelphij	RUE_UNLOCK(sc);
895285612Sdelphij}
896285612Sdelphij
897285612Sdelphijstatic void
898285612Sdelphijrue_stop(struct usb_ether *ue)
899285612Sdelphij{
900285612Sdelphij	struct rue_softc *sc = uether_getsc(ue);
901285612Sdelphij	struct ifnet *ifp = uether_getifp(ue);
90282505Sroberto
90382505Sroberto	RUE_LOCK_ASSERT(sc, MA_OWNED);
90482505Sroberto
90582505Sroberto	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
906285612Sdelphij	sc->sc_flags &= ~RUE_FLAG_LINK;
90782505Sroberto
90882505Sroberto	/*
90982505Sroberto	 * stop all the transfers, if not already stopped:
91082505Sroberto	 */
91182505Sroberto	usbd_transfer_stop(sc->sc_xfer[RUE_BULK_DT_WR]);
91282505Sroberto	usbd_transfer_stop(sc->sc_xfer[RUE_BULK_DT_RD]);
91382505Sroberto	usbd_transfer_stop(sc->sc_xfer[RUE_INTR_DT_RD]);
91482505Sroberto
91582505Sroberto	rue_csr_write_1(sc, RUE_CR, 0x00);
916285612Sdelphij
91782505Sroberto	rue_reset(sc);
91882505Sroberto}
91954359Sroberto