1139825Simp/*-
21541Srgrimes * Copyright (c) 2001-2003, Shunsuke Akiyama <akiyama@FreeBSD.org>.
31541Srgrimes * Copyright (c) 1997, 1998, 1999, 2000 Bill Paul <wpaul@ee.columbia.edu>.
41541Srgrimes * All rights reserved.
51541Srgrimes *
61541Srgrimes * Redistribution and use in source and binary forms, with or without
71541Srgrimes * modification, are permitted provided that the following conditions
81541Srgrimes * are met:
91541Srgrimes * 1. Redistributions of source code must retain the above copyright
101541Srgrimes *    notice, this list of conditions and the following disclaimer.
111541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
121541Srgrimes *    notice, this list of conditions and the following disclaimer in the
131541Srgrimes *    documentation and/or other materials provided with the distribution.
141541Srgrimes *
151541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
161541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
171541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
181541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
191541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
201541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
211541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
221541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
231541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
241541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
251541Srgrimes * SUCH DAMAGE.
261541Srgrimes */
271541Srgrimes/*-
281541Srgrimes * Copyright (c) 1997, 1998, 1999, 2000
2922521Sdyson *	Bill Paul <wpaul@ee.columbia.edu>.  All rights reserved.
3050477Speter *
311541Srgrimes * Redistribution and use in source and binary forms, with or without
321541Srgrimes * modification, are permitted provided that the following conditions
332176Spaul * are met:
34262779Spfg * 1. Redistributions of source code must retain the above copyright
352176Spaul *    notice, this list of conditions and the following disclaimer.
36243245Strasz * 2. Redistributions in binary form must reproduce the above copyright
37243250Strasz *    notice, this list of conditions and the following disclaimer in the
38243245Strasz *    documentation and/or other materials provided with the distribution.
391541Srgrimes * 3. All advertising materials mentioning features or use of this software
4096755Strhodes *    must display the following acknowledgement:
4196755Strhodes *	This product includes software developed by Bill Paul.
421541Srgrimes * 4. Neither the name of the author nor the names of any co-contributors
431541Srgrimes *    may be used to endorse or promote products derived from this software
4496755Strhodes *    without specific prior written permission.
451541Srgrimes *
461541Srgrimes * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
471541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
481541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
491541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
501541Srgrimes * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5196755Strhodes * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
521541Srgrimes * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
531541Srgrimes * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
541541Srgrimes * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
551541Srgrimes * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
561541Srgrimes * THE POSSIBILITY OF SUCH DAMAGE.
571541Srgrimes */
581541Srgrimes
591541Srgrimes#include <sys/cdefs.h>
6098542Smckusick__FBSDID("$FreeBSD$");
6198542Smckusick
6298542Smckusick/*
6398542Smckusick * RealTek RTL8150 USB to fast ethernet controller driver.
6498542Smckusick * Datasheet is available from
6598542Smckusick * ftp://ftp.realtek.com.tw/lancard/data_sheet/8150/.
6698542Smckusick */
6798542Smckusick
6898542Smckusick#include <sys/stdint.h>
6998542Smckusick#include <sys/stddef.h>
701541Srgrimes#include <sys/param.h>
71262779Spfg#include <sys/queue.h>
72262779Spfg#include <sys/types.h>
73262779Spfg#include <sys/systm.h>
74262779Spfg#include <sys/kernel.h>
75262779Spfg#include <sys/bus.h>
76262779Spfg#include <sys/module.h>
7798542Smckusick#include <sys/lock.h>
781541Srgrimes#include <sys/mutex.h>
7998542Smckusick#include <sys/condvar.h>
8098542Smckusick#include <sys/sysctl.h>
8198542Smckusick#include <sys/sx.h>
82262779Spfg#include <sys/unistd.h>
8398542Smckusick#include <sys/callout.h>
841541Srgrimes#include <sys/malloc.h>
851541Srgrimes#include <sys/priv.h>
868876Srgrimes
871541Srgrimes#include <dev/usb/usb.h>
8813765Smpp#include <dev/usb/usbdi.h>
891541Srgrimes#include <dev/usb/usbdi_util.h>
901541Srgrimes#include "usbdevs.h"
911541Srgrimes
921541Srgrimes#define	USB_DEBUG_VAR rue_debug
931541Srgrimes#include <dev/usb/usb_debug.h>
9496755Strhodes#include <dev/usb/usb_process.h>
951541Srgrimes
961541Srgrimes#include <dev/usb/net/usb_ethernet.h>
971541Srgrimes#include <dev/usb/net/if_ruereg.h>
981541Srgrimes
9996755Strhodes#ifdef USB_DEBUG
1001541Srgrimesstatic int rue_debug = 0;
1011541Srgrimes
1021541Srgrimesstatic SYSCTL_NODE(_hw_usb, OID_AUTO, rue, CTLFLAG_RW, 0, "USB rue");
1031541SrgrimesSYSCTL_INT(_hw_usb_rue, OID_AUTO, debug, CTLFLAG_RW,
1041541Srgrimes    &rue_debug, 0, "Debug level");
1051541Srgrimes#endif
1061541Srgrimes
1071541Srgrimes/*
1081541Srgrimes * Various supported device vendors/products.
109179295Srodrigc */
110179295Srodrigc
1111541Srgrimesstatic const STRUCT_USB_HOST_ID rue_devs[] = {
112262779Spfg	{USB_VPI(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAKTX, 0)},
1131541Srgrimes	{USB_VPI(USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_USBKR100, 0)},
1141541Srgrimes	{USB_VPI(USB_VENDOR_OQO, USB_PRODUCT_OQO_ETHER01, 0)},
11596755Strhodes};
1168876Srgrimes
1171541Srgrimes/* prototypes */
11822521Sdyson
119262779Spfgstatic device_probe_t rue_probe;
12022521Sdysonstatic device_attach_t rue_attach;
12122521Sdysonstatic device_detach_t rue_detach;
122108970Sgordon
123108970Sgordonstatic miibus_readreg_t rue_miibus_readreg;
124108970Sgordonstatic miibus_writereg_t rue_miibus_writereg;
125262779Spfgstatic miibus_statchg_t rue_miibus_statchg;
126108970Sgordon
127108970Sgordonstatic usb_callback_t rue_intr_callback;
12871073Siedowsestatic usb_callback_t rue_bulk_read_callback;
12971073Siedowsestatic usb_callback_t rue_bulk_write_callback;
13088025Siedowse
13171073Siedowsestatic uether_fn_t rue_attach_post;
13271073Siedowsestatic uether_fn_t rue_init;
13371073Siedowsestatic uether_fn_t rue_stop;
13471073Siedowsestatic uether_fn_t rue_start;
13571073Siedowsestatic uether_fn_t rue_tick;
13675377Smckusickstatic uether_fn_t rue_setmulti;
13775377Smckusickstatic uether_fn_t rue_setpromisc;
13888025Siedowse
13988025Siedowsestatic int	rue_read_mem(struct rue_softc *, uint16_t, void *, int);
14088025Siedowsestatic int	rue_write_mem(struct rue_softc *, uint16_t, void *, int);
1411541Srgrimesstatic uint8_t	rue_csr_read_1(struct rue_softc *, uint16_t);
14288025Siedowsestatic uint16_t	rue_csr_read_2(struct rue_softc *, uint16_t);
1431541Srgrimesstatic int	rue_csr_write_1(struct rue_softc *, uint16_t, uint8_t);
1441541Srgrimesstatic int	rue_csr_write_2(struct rue_softc *, uint16_t, uint16_t);
1451541Srgrimesstatic int	rue_csr_write_4(struct rue_softc *, int, uint32_t);
1461541Srgrimes
1471541Srgrimesstatic void	rue_reset(struct rue_softc *);
1481541Srgrimesstatic int	rue_ifmedia_upd(struct ifnet *);
1491541Srgrimesstatic void	rue_ifmedia_sts(struct ifnet *, struct ifmediareq *);
150262779Spfg
1511541Srgrimesstatic const struct usb_config rue_config[RUE_N_TRANSFER] = {
1521541Srgrimes
15396755Strhodes	[RUE_BULK_DT_WR] = {
1541541Srgrimes		.type = UE_BULK,
1551541Srgrimes		.endpoint = UE_ADDR_ANY,
1561541Srgrimes		.direction = UE_DIR_OUT,
15796755Strhodes		.bufsize = MCLBYTES,
1581541Srgrimes		.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
1591541Srgrimes		.callback = rue_bulk_write_callback,
1601541Srgrimes		.timeout = 10000,	/* 10 seconds */
1611541Srgrimes	},
1621541Srgrimes
1631541Srgrimes	[RUE_BULK_DT_RD] = {
164262779Spfg		.type = UE_BULK,
165262779Spfg		.endpoint = UE_ADDR_ANY,
1661541Srgrimes		.direction = UE_DIR_IN,
1671541Srgrimes		.bufsize = (MCLBYTES + 4),
16875377Smckusick		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
16975377Smckusick		.callback = rue_bulk_read_callback,
17075377Smckusick		.timeout = 0,	/* no timeout */
17175377Smckusick	},
17275377Smckusick
17375377Smckusick	[RUE_INTR_DT_RD] = {
174129895Skrion		.type = UE_INTERRUPT,
17575377Smckusick		.endpoint = UE_ADDR_ANY,
176262779Spfg		.direction = UE_DIR_IN,
177262779Spfg		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
17875377Smckusick		.bufsize = 0,	/* use wMaxPacketSize */
17975377Smckusick		.callback = rue_intr_callback,
18062553Smckusick	},
18162553Smckusick};
18262553Smckusick
18362553Smckusickstatic device_method_t rue_methods[] = {
18462553Smckusick	/* Device interface */
18562553Smckusick	DEVMETHOD(device_probe, rue_probe),
18662553Smckusick	DEVMETHOD(device_attach, rue_attach),
187262779Spfg	DEVMETHOD(device_detach, rue_detach),
18862553Smckusick
18962553Smckusick	/* MII interface */
19062553Smckusick	DEVMETHOD(miibus_readreg, rue_miibus_readreg),
19162553Smckusick	DEVMETHOD(miibus_writereg, rue_miibus_writereg),
19262553Smckusick	DEVMETHOD(miibus_statchg, rue_miibus_statchg),
19362553Smckusick
19462553Smckusick	DEVMETHOD_END
19562553Smckusick};
19662553Smckusick
19762553Smckusickstatic driver_t rue_driver = {
19862553Smckusick	.name = "rue",
19962553Smckusick	.methods = rue_methods,
200262779Spfg	.size = sizeof(struct rue_softc),
201262779Spfg};
20262553Smckusick
20362553Smckusickstatic devclass_t rue_devclass;
20474548Smckusick
20574548SmckusickDRIVER_MODULE_ORDERED(rue, uhub, rue_driver, rue_devclass, NULL, NULL,
20674548Smckusick    SI_ORDER_ANY);
20774548SmckusickDRIVER_MODULE(miibus, rue, miibus_driver, miibus_devclass, NULL, NULL);
20874548SmckusickMODULE_DEPEND(rue, uether, 1, 1, 1);
20974548SmckusickMODULE_DEPEND(rue, usb, 1, 1, 1);
21074548SmckusickMODULE_DEPEND(rue, ether, 1, 1, 1);
21174548SmckusickMODULE_DEPEND(rue, miibus, 1, 1, 1);
212142123SdelphijMODULE_VERSION(rue, 1);
213142123Sdelphij
214142123Sdelphijstatic const struct usb_ether_methods rue_ue_methods = {
215142123Sdelphij	.ue_attach_post = rue_attach_post,
216142123Sdelphij	.ue_start = rue_start,
217262779Spfg	.ue_init = rue_init,
218202113Smckusick	.ue_stop = rue_stop,
219202113Smckusick	.ue_tick = rue_tick,
220224061Smckusick	.ue_setmulti = rue_setmulti,
221224061Smckusick	.ue_setpromisc = rue_setpromisc,
222224061Smckusick	.ue_mii_upd = rue_ifmedia_upd,
22374548Smckusick	.ue_mii_sts = rue_ifmedia_sts,
22474548Smckusick};
22574548Smckusick
22674548Smckusick#define	RUE_SETBIT(sc, reg, x) \
22798542Smckusick	rue_csr_write_1(sc, reg, rue_csr_read_1(sc, reg) | (x))
22874548Smckusick
22998542Smckusick#define	RUE_CLRBIT(sc, reg, x) \
23098542Smckusick	rue_csr_write_1(sc, reg, rue_csr_read_1(sc, reg) & ~(x))
23198542Smckusick
23298542Smckusickstatic int
23398542Smckusickrue_read_mem(struct rue_softc *sc, uint16_t addr, void *buf, int len)
23474548Smckusick{
23574548Smckusick	struct usb_device_request req;
23674548Smckusick
237322860Smckusick	req.bmRequestType = UT_READ_VENDOR_DEVICE;
238322860Smckusick	req.bRequest = UR_SET_ADDRESS;
239322860Smckusick	USETW(req.wValue, addr);
240322860Smckusick	USETW(req.wIndex, 0);
241322860Smckusick	USETW(req.wLength, len);
242322860Smckusick
243322860Smckusick	return (uether_do_request(&sc->sc_ue, &req, buf, 1000));
244322860Smckusick}
245322860Smckusick
246322860Smckusickstatic int
247322860Smckusickrue_write_mem(struct rue_softc *sc, uint16_t addr, void *buf, int len)
248322860Smckusick{
249322860Smckusick	struct usb_device_request req;
250322860Smckusick
2511541Srgrimes	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
2521541Srgrimes	req.bRequest = UR_SET_ADDRESS;
2531541Srgrimes	USETW(req.wValue, addr);
2541541Srgrimes	USETW(req.wIndex, 0);
2551541Srgrimes	USETW(req.wLength, len);
2561541Srgrimes
25722521Sdyson	return (uether_do_request(&sc->sc_ue, &req, buf, 1000));
25822521Sdyson}
25922521Sdyson
26022521Sdysonstatic uint8_t
2611541Srgrimesrue_csr_read_1(struct rue_softc *sc, uint16_t reg)
26298542Smckusick{
26398542Smckusick	uint8_t val;
26498542Smckusick
26598542Smckusick	rue_read_mem(sc, reg, &val, 1);
26698542Smckusick	return (val);
26798542Smckusick}
26898542Smckusick
26998542Smckusickstatic uint16_t
2701541Srgrimesrue_csr_read_2(struct rue_softc *sc, uint16_t reg)
2711541Srgrimes{
27296755Strhodes	uint8_t val[2];
2731541Srgrimes
2741541Srgrimes	rue_read_mem(sc, reg, &val, 2);
27596755Strhodes	return (UGETW(val));
27622521Sdyson}
27798542Smckusick
27898542Smckusickstatic int
27998542Smckusickrue_csr_write_1(struct rue_softc *sc, uint16_t reg, uint8_t val)
28098542Smckusick{
28198542Smckusick	return (rue_write_mem(sc, reg, &val, 1));
28298542Smckusick}
28398542Smckusick
28498542Smckusickstatic int
28598542Smckusickrue_csr_write_2(struct rue_softc *sc, uint16_t reg, uint16_t val)
286203763Smckusick{
28722521Sdyson	uint8_t temp[2];
28822521Sdyson
28922521Sdyson	USETW(temp, val);
2901541Srgrimes	return (rue_write_mem(sc, reg, &temp, 2));
29122521Sdyson}
29298542Smckusick
29398542Smckusickstatic int
2941541Srgrimesrue_csr_write_4(struct rue_softc *sc, int reg, uint32_t val)
29522521Sdyson{
29622521Sdyson	uint8_t temp[4];
29722521Sdyson
29822521Sdyson	USETDW(temp, val);
2991541Srgrimes	return (rue_write_mem(sc, reg, &temp, 4));
30022521Sdyson}
30122521Sdyson
3021541Srgrimesstatic int
30322521Sdysonrue_miibus_readreg(device_t dev, int phy, int reg)
30422521Sdyson{
30522521Sdyson	struct rue_softc *sc = device_get_softc(dev);
30698542Smckusick	uint16_t rval;
30798542Smckusick	uint16_t ruereg;
30822521Sdyson	int locked;
309203784Smckusick
31098542Smckusick	if (phy != 0)		/* RTL8150 supports PHY == 0, only */
3111541Srgrimes		return (0);
31222521Sdyson
31398542Smckusick	locked = mtx_owned(&sc->sc_mtx);
31498542Smckusick	if (!locked)
31598542Smckusick		RUE_LOCK(sc);
31624171Sbde
3171541Srgrimes	switch (reg) {
31898542Smckusick	case MII_BMCR:
31922521Sdyson		ruereg = RUE_BMCR;
32022521Sdyson		break;
32198542Smckusick	case MII_BMSR:
32298542Smckusick		ruereg = RUE_BMSR;
32398542Smckusick		break;
32498542Smckusick	case MII_ANAR:
32598542Smckusick		ruereg = RUE_ANAR;
326203763Smckusick		break;
32798542Smckusick	case MII_ANER:
3281541Srgrimes		ruereg = RUE_AER;
32998542Smckusick		break;
3301541Srgrimes	case MII_ANLPAR:
33122521Sdyson		ruereg = RUE_ANLP;
33296755Strhodes		break;
33322521Sdyson	case MII_PHYIDR1:
334107294Smckusick	case MII_PHYIDR2:
33522521Sdyson		rval = 0;
336108970Sgordon		goto done;
337109034Sgordon	default:
338109053Smarcel		if (RUE_REG_MIN <= reg && reg <= RUE_REG_MAX) {
3391541Srgrimes			rval = rue_csr_read_1(sc, reg);
34022521Sdyson			goto done;
34171073Siedowse		}
342140702Sjeff		device_printf(sc->sc_ue.ue_dev, "bad phy register\n");
343140702Sjeff		rval = 0;
344140702Sjeff		goto done;
345140702Sjeff	}
34698542Smckusick
34798542Smckusick	rval = rue_csr_read_2(sc, ruereg);
348163841Spjddone:
349242379Strasz	if (!locked)
350248623Smckusick		RUE_UNLOCK(sc);
351248623Smckusick	return (rval);
352107294Smckusick}
353140702Sjeff
35498542Smckusickstatic int
35598542Smckusickrue_miibus_writereg(device_t dev, int phy, int reg, int data)
35698542Smckusick{
35798542Smckusick	struct rue_softc *sc = device_get_softc(dev);
358140702Sjeff	uint16_t ruereg;
359203763Smckusick	int locked;
360227382Sgleb
361203763Smckusick	if (phy != 0)		/* RTL8150 supports PHY == 0, only */
362203763Smckusick		return (0);
36398542Smckusick
364207141Sjeff	locked = mtx_owned(&sc->sc_mtx);
365207141Sjeff	if (!locked)
366207141Sjeff		RUE_LOCK(sc);
367107294Smckusick
36822521Sdyson	switch (reg) {
36922521Sdyson	case MII_BMCR:
37098542Smckusick		ruereg = RUE_BMCR;
37122521Sdyson		break;
37222521Sdyson	case MII_BMSR:
37322521Sdyson		ruereg = RUE_BMSR;
37422521Sdyson		break;
37598542Smckusick	case MII_ANAR:
37698542Smckusick		ruereg = RUE_ANAR;
37798542Smckusick		break;
37898542Smckusick	case MII_ANER:
37922521Sdyson		ruereg = RUE_AER;
3801541Srgrimes		break;
38122521Sdyson	case MII_ANLPAR:
382109053Smarcel		ruereg = RUE_ANLP;
383109053Smarcel		break;
384109053Smarcel	case MII_PHYIDR1:
385109053Smarcel	case MII_PHYIDR2:
386109053Smarcel		goto done;
3871541Srgrimes	default:
38813765Smpp		if (RUE_REG_MIN <= reg && reg <= RUE_REG_MAX) {
3891541Srgrimes			rue_csr_write_1(sc, reg, data);
39098542Smckusick			goto done;
39198542Smckusick		}
392134011Sjhb		device_printf(sc->sc_ue.ue_dev, " bad phy register\n");
3931541Srgrimes		goto done;
394262779Spfg	}
395262779Spfg	rue_csr_write_2(sc, ruereg, data);
39634266Sjuliandone:
3971541Srgrimes	if (!locked)
3981541Srgrimes		RUE_UNLOCK(sc);
3991541Srgrimes	return (0);
400262779Spfg}
401262779Spfg
4021541Srgrimesstatic void
4031541Srgrimesrue_miibus_statchg(device_t dev)
40434266Sjulian{
40575503Smckusick	/*
40698542Smckusick	 * When the code below is enabled the card starts doing weird
40798542Smckusick	 * things after link going from UP to DOWN and back UP.
40898542Smckusick	 *
40975503Smckusick	 * Looks like some of register writes below messes up PHY
41075503Smckusick	 * interface.
41175503Smckusick	 *
41275503Smckusick	 * No visible regressions were found after commenting this code
41375503Smckusick	 * out, so that disable it for good.
41475503Smckusick	 */
41575503Smckusick#if 0
41698542Smckusick	struct rue_softc *sc = device_get_softc(dev);
41798542Smckusick	struct mii_data *mii = GET_MII(sc);
41898542Smckusick	uint16_t bmcr;
41998542Smckusick	int locked;
42098542Smckusick
421105112Srwatson	locked = mtx_owned(&sc->sc_mtx);
422200796Strasz	if (!locked)
423200796Strasz		RUE_LOCK(sc);
424105112Srwatson
425200796Strasz	RUE_CLRBIT(sc, RUE_CR, (RUE_CR_RE | RUE_CR_TE));
426200796Strasz
427200796Strasz	bmcr = rue_csr_read_2(sc, RUE_BMCR);
428200796Strasz
429200796Strasz	if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX)
43034266Sjulian		bmcr |= RUE_BMCR_SPD_SET;
431262779Spfg	else
432262779Spfg		bmcr &= ~RUE_BMCR_SPD_SET;
433262779Spfg
434207141Sjeff	if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX)
435262779Spfg		bmcr |= RUE_BMCR_DUPLEX;
436262779Spfg	else
437262779Spfg		bmcr &= ~RUE_BMCR_DUPLEX;
438262779Spfg
439262779Spfg	rue_csr_write_2(sc, RUE_BMCR, bmcr);
440262779Spfg
441216796Skib	RUE_SETBIT(sc, RUE_CR, (RUE_CR_RE | RUE_CR_TE));
44234266Sjulian
44334266Sjulian	if (!locked)
44488138Smckusick		RUE_UNLOCK(sc);
44588138Smckusick#endif
44688138Smckusick}
44789450Smckusick
448140702Sjeffstatic void
449140702Sjeffrue_setpromisc(struct usb_ether *ue)
450140702Sjeff{
451140702Sjeff	struct rue_softc *sc = uether_getsc(ue);
452140702Sjeff	struct ifnet *ifp = uether_getifp(ue);
453140702Sjeff
454140702Sjeff	RUE_LOCK_ASSERT(sc, MA_OWNED);
455140702Sjeff
45688138Smckusick	/* If we want promiscuous mode, set the allframes bit. */
45788138Smckusick	if (ifp->if_flags & IFF_PROMISC)
4581541Srgrimes		RUE_SETBIT(sc, RUE_RCR, RUE_RCR_AAP);
4591541Srgrimes	else
4608876Srgrimes		RUE_CLRBIT(sc, RUE_RCR, RUE_RCR_AAP);
4611541Srgrimes}
4621541Srgrimes
463262779Spfg/*
46422521Sdyson * Program the 64-bit multicast hash filter.
46598542Smckusick */
46698542Smckusickstatic void
4671541Srgrimesrue_setmulti(struct usb_ether *ue)
46898542Smckusick{
4691541Srgrimes	struct rue_softc *sc = uether_getsc(ue);
47022521Sdyson	struct ifnet *ifp = uether_getifp(ue);
47198542Smckusick	uint16_t rxcfg;
4721541Srgrimes	int h = 0;
4731541Srgrimes	uint32_t hashes[2] = { 0, 0 };
47498542Smckusick	struct ifmultiaddr *ifma;
47598542Smckusick	int mcnt = 0;
476262779Spfg
47798542Smckusick	RUE_LOCK_ASSERT(sc, MA_OWNED);
47898542Smckusick
4791541Srgrimes	rxcfg = rue_csr_read_2(sc, RUE_RCR);
4801541Srgrimes
481262779Spfg	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
4821541Srgrimes		rxcfg |= (RUE_RCR_AAM | RUE_RCR_AAP);
4831541Srgrimes		rxcfg &= ~RUE_RCR_AM;
48496755Strhodes		rue_csr_write_2(sc, RUE_RCR, rxcfg);
4851541Srgrimes		rue_csr_write_4(sc, RUE_MAR0, 0xFFFFFFFF);
4861541Srgrimes		rue_csr_write_4(sc, RUE_MAR4, 0xFFFFFFFF);
48722521Sdyson		return;
48822521Sdyson	}
48922521Sdyson
49098542Smckusick	/* first, zot all the existing hash bits */
491203763Smckusick	rue_csr_write_4(sc, RUE_MAR0, 0);
49298542Smckusick	rue_csr_write_4(sc, RUE_MAR4, 0);
49398542Smckusick
494203763Smckusick	/* now program new ones */
495203763Smckusick	if_maddr_rlock(ifp);
496203763Smckusick	TAILQ_FOREACH (ifma, &ifp->if_multiaddrs, ifma_link)
497203763Smckusick	{
498203763Smckusick		if (ifma->ifma_addr->sa_family != AF_LINK)
499203763Smckusick			continue;
50098542Smckusick		h = ether_crc32_be(LLADDR((struct sockaddr_dl *)
50198542Smckusick		    ifma->ifma_addr), ETHER_ADDR_LEN) >> 26;
502203763Smckusick		if (h < 32)
503203763Smckusick			hashes[0] |= (1 << h);
504203763Smckusick		else
505203763Smckusick			hashes[1] |= (1 << (h - 32));
506203763Smckusick		mcnt++;
507203763Smckusick	}
508203763Smckusick	if_maddr_runlock(ifp);
509203763Smckusick
510203763Smckusick	if (mcnt)
511163841Spjd		rxcfg |= RUE_RCR_AM;
51298542Smckusick	else
51398542Smckusick		rxcfg &= ~RUE_RCR_AM;
51422521Sdyson
5151541Srgrimes	rxcfg &= ~(RUE_RCR_AAM | RUE_RCR_AAP);
5161541Srgrimes
51722521Sdyson	rue_csr_write_2(sc, RUE_RCR, rxcfg);
5181541Srgrimes	rue_csr_write_4(sc, RUE_MAR0, hashes[0]);
5191541Srgrimes	rue_csr_write_4(sc, RUE_MAR4, hashes[1]);
5201541Srgrimes}
521262779Spfg
522262779Spfgstatic void
52398542Smckusickrue_reset(struct rue_softc *sc)
524262779Spfg{
52598542Smckusick	int i;
526262779Spfg
52722521Sdyson	rue_csr_write_1(sc, RUE_CR, RUE_CR_SOFT_RST);
528262779Spfg
529127818Smux	for (i = 0; i != RUE_TIMEOUT; i++) {
5301541Srgrimes		if (uether_pause(&sc->sc_ue, hz / 1000))
5311541Srgrimes			break;
53296755Strhodes		if (!(rue_csr_read_1(sc, RUE_CR) & RUE_CR_SOFT_RST))
53396755Strhodes			break;
5341541Srgrimes	}
535136336Snjl	if (i == RUE_TIMEOUT)
5361541Srgrimes		device_printf(sc->sc_ue.ue_dev, "reset never completed\n");
5371541Srgrimes
5381541Srgrimes	uether_pause(&sc->sc_ue, hz / 100);
5391541Srgrimes}
54096755Strhodes
5411541Srgrimesstatic void
542111238Smckusickrue_attach_post(struct usb_ether *ue)
543248623Smckusick{
544248623Smckusick	struct rue_softc *sc = uether_getsc(ue);
5451541Srgrimes
5461541Srgrimes	/* reset the adapter */
5471541Srgrimes	rue_reset(sc);
5481541Srgrimes
549262779Spfg	/* get station address from the EEPROM */
55098542Smckusick	rue_read_mem(sc, RUE_EEPROM_IDR0, ue->ue_eaddr, ETHER_ADDR_LEN);
55198542Smckusick}
5521541Srgrimes
5531541Srgrimes/*
5541541Srgrimes * Probe for a RTL8150 chip.
55596755Strhodes */
5561541Srgrimesstatic int
55796755Strhodesrue_probe(device_t dev)
5581541Srgrimes{
559203763Smckusick	struct usb_attach_arg *uaa = device_get_ivars(dev);
5601541Srgrimes
561203763Smckusick	if (uaa->usb_mode != USB_MODE_HOST)
562203763Smckusick		return (ENXIO);
563203763Smckusick	if (uaa->info.bConfigIndex != RUE_CONFIG_IDX)
5641541Srgrimes		return (ENXIO);
5651541Srgrimes	if (uaa->info.bIfaceIndex != RUE_IFACE_IDX)
56696755Strhodes		return (ENXIO);
56796755Strhodes
5681541Srgrimes	return (usbd_lookup_id_by_uaa(rue_devs, sizeof(rue_devs), uaa));
5691541Srgrimes}
5701541Srgrimes
5711541Srgrimes/*
5721541Srgrimes * Attach the interface. Allocate softc structures, do ifmedia
5731541Srgrimes * setup and ethernet/BPF attach.
5741541Srgrimes */
5751541Srgrimesstatic int
576262779Spfgrue_attach(device_t dev)
5771541Srgrimes{
5781541Srgrimes	struct usb_attach_arg *uaa = device_get_ivars(dev);
5791541Srgrimes	struct rue_softc *sc = device_get_softc(dev);
5801541Srgrimes	struct usb_ether *ue = &sc->sc_ue;
5811541Srgrimes	uint8_t iface_index;
5821541Srgrimes	int error;
5831541Srgrimes
584262779Spfg	device_set_usb_desc(dev);
5851541Srgrimes	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
586262779Spfg
5871541Srgrimes	iface_index = RUE_IFACE_IDX;
588262779Spfg	error = usbd_transfer_setup(uaa->device, &iface_index,
589111238Smckusick	    sc->sc_xfer, rue_config, RUE_N_TRANSFER,
590262779Spfg	    sc, &sc->sc_mtx);
591111238Smckusick	if (error) {
59218899Sbde		device_printf(dev, "allocating USB transfers failed\n");
593262779Spfg		goto detach;
5941541Srgrimes	}
595262779Spfg
5961541Srgrimes	ue->ue_sc = sc;
597262779Spfg	ue->ue_dev = dev;
5981541Srgrimes	ue->ue_udev = uaa->device;
599262779Spfg	ue->ue_mtx = &sc->sc_mtx;
6001541Srgrimes	ue->ue_methods = &rue_ue_methods;
601262779Spfg
6021541Srgrimes	error = uether_ifattach(ue);
603262779Spfg	if (error) {
6041541Srgrimes		device_printf(dev, "could not attach interface\n");
605262779Spfg		goto detach;
6061541Srgrimes	}
607262779Spfg	return (0);			/* success */
6081541Srgrimes
609262779Spfgdetach:
6101541Srgrimes	rue_detach(dev);
6111541Srgrimes	return (ENXIO);			/* failure */
6121541Srgrimes}
6131541Srgrimes
61422521Sdysonstatic int
6151541Srgrimesrue_detach(device_t dev)
616262779Spfg{
6171541Srgrimes	struct rue_softc *sc = device_get_softc(dev);
61858155Smckusick	struct usb_ether *ue = &sc->sc_ue;
619111238Smckusick
6201541Srgrimes	usbd_transfer_unsetup(sc->sc_xfer, RUE_N_TRANSFER);
6211541Srgrimes	uether_ifdetach(ue);
62296755Strhodes	mtx_destroy(&sc->sc_mtx);
6231541Srgrimes
624262779Spfg	return (0);
62518899Sbde}
6261541Srgrimes
6271541Srgrimesstatic void
628262779Spfgrue_intr_callback(struct usb_xfer *xfer, usb_error_t error)
62934266Sjulian{
63034266Sjulian	struct rue_softc *sc = usbd_xfer_softc(xfer);
63134266Sjulian	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
6321541Srgrimes	struct rue_intrpkt pkt;
6331541Srgrimes	struct usb_page_cache *pc;
634215113Skib	int actlen;
635215113Skib
636215113Skib	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
637215113Skib
638215113Skib	switch (USB_GET_STATE(xfer)) {
639207141Sjeff	case USB_ST_TRANSFERRED:
640207141Sjeff
641207141Sjeff		if (ifp && (ifp->if_drv_flags & IFF_DRV_RUNNING) &&
642207141Sjeff		    actlen >= (int)sizeof(pkt)) {
643207141Sjeff
644207141Sjeff			pc = usbd_xfer_get_frame(xfer, 0);
645207141Sjeff			usbd_copy_out(pc, 0, &pkt, sizeof(pkt));
646207141Sjeff
647207141Sjeff			ifp->if_ierrors += pkt.rue_rxlost_cnt;
648207141Sjeff			ifp->if_ierrors += pkt.rue_crcerr_cnt;
649207141Sjeff			ifp->if_collisions += pkt.rue_col_cnt;
650207141Sjeff		}
651207141Sjeff		/* FALLTHROUGH */
652207141Sjeff	case USB_ST_SETUP:
653207141Sjefftr_setup:
654207141Sjeff		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
655207141Sjeff		usbd_transfer_submit(xfer);
656207141Sjeff		return;
657207141Sjeff
658207141Sjeff	default:			/* Error */
659207141Sjeff		if (error != USB_ERR_CANCELLED) {
660207141Sjeff			/* try to clear stall first */
661207141Sjeff			usbd_xfer_set_stall(xfer);
662207141Sjeff			goto tr_setup;
663215113Skib		}
664215113Skib		return;
665215113Skib	}
666215113Skib}
667215113Skib
668215113Skibstatic void
669215113Skibrue_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
670215113Skib{
671215113Skib	struct rue_softc *sc = usbd_xfer_softc(xfer);
672215113Skib	struct usb_ether *ue = &sc->sc_ue;
673215113Skib	struct ifnet *ifp = uether_getifp(ue);
674207141Sjeff	struct usb_page_cache *pc;
67522521Sdyson	uint16_t status;
6761541Srgrimes	int actlen;
6771541Srgrimes
6781541Srgrimes	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
6791541Srgrimes
6801541Srgrimes	switch (USB_GET_STATE(xfer)) {
681207141Sjeff	case USB_ST_TRANSFERRED:
682207141Sjeff
683207141Sjeff		if (actlen < 4) {
684207141Sjeff			ifp->if_ierrors++;
685207141Sjeff			goto tr_setup;
686207141Sjeff		}
687207141Sjeff		pc = usbd_xfer_get_frame(xfer, 0);
688207141Sjeff		usbd_copy_out(pc, actlen - 4, &status, sizeof(status));
689207141Sjeff		actlen -= 4;
690222958Sjeff
691207141Sjeff		/* check recieve packet was valid or not */
692207141Sjeff		status = le16toh(status);
693207141Sjeff		if ((status & RUE_RXSTAT_VALID) == 0) {
694207141Sjeff			ifp->if_ierrors++;
695207141Sjeff			goto tr_setup;
696207141Sjeff		}
697207141Sjeff		uether_rxbuf(ue, pc, 0, actlen);
698207141Sjeff		/* FALLTHROUGH */
699207141Sjeff	case USB_ST_SETUP:
700212617Smckusicktr_setup:
701207141Sjeff		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
702207141Sjeff		usbd_transfer_submit(xfer);
703207141Sjeff		uether_rxflush(ue);
704207141Sjeff		return;
705207141Sjeff
706207141Sjeff	default:			/* Error */
707207141Sjeff		DPRINTF("bulk read error, %s\n",
708207141Sjeff		    usbd_errstr(error));
709218602Skib
710207141Sjeff		if (error != USB_ERR_CANCELLED) {
711207141Sjeff			/* try to clear stall first */
712207141Sjeff			usbd_xfer_set_stall(xfer);
713207141Sjeff			goto tr_setup;
714207141Sjeff		}
715207141Sjeff		return;
716207141Sjeff	}
717207141Sjeff}
718207141Sjeff
719227382Sglebstatic void
720227382Sglebrue_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
721207141Sjeff{
722207141Sjeff	struct rue_softc *sc = usbd_xfer_softc(xfer);
723227382Sgleb	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
724207141Sjeff	struct usb_page_cache *pc;
725207141Sjeff	struct mbuf *m;
726207141Sjeff	int temp_len;
727207141Sjeff
728207141Sjeff	switch (USB_GET_STATE(xfer)) {
729207141Sjeff	case USB_ST_TRANSFERRED:
730207141Sjeff		DPRINTFN(11, "transfer complete\n");
731207141Sjeff		ifp->if_opackets++;
732207141Sjeff
733227382Sgleb		/* FALLTHROUGH */
734227382Sgleb	case USB_ST_SETUP:
735207141Sjefftr_setup:
736227382Sgleb		if ((sc->sc_flags & RUE_FLAG_LINK) == 0) {
737227382Sgleb			/*
738207141Sjeff			 * don't send anything if there is no link !
739207141Sjeff			 */
740207141Sjeff			return;
741207141Sjeff		}
742207141Sjeff		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
743207141Sjeff
744207141Sjeff		if (m == NULL)
745207141Sjeff			return;
746207141Sjeff		if (m->m_pkthdr.len > MCLBYTES)
747207141Sjeff			m->m_pkthdr.len = MCLBYTES;
748207141Sjeff		temp_len = m->m_pkthdr.len;
749207141Sjeff
750207141Sjeff		pc = usbd_xfer_get_frame(xfer, 0);
751207141Sjeff		usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len);
752207141Sjeff
753207141Sjeff		/*
754207141Sjeff		 * This is an undocumented behavior.
755207141Sjeff		 * RTL8150 chip doesn't send frame length smaller than
756222958Sjeff		 * RUE_MIN_FRAMELEN (60) byte packet.
757207141Sjeff		 */
758207141Sjeff		if (temp_len < RUE_MIN_FRAMELEN) {
759207141Sjeff			usbd_frame_zero(pc, temp_len,
760207141Sjeff			    RUE_MIN_FRAMELEN - temp_len);
761227382Sgleb			temp_len = RUE_MIN_FRAMELEN;
762207141Sjeff		}
763207141Sjeff		usbd_xfer_set_frame_len(xfer, 0, temp_len);
764207141Sjeff
765207141Sjeff		/*
766207141Sjeff		 * if there's a BPF listener, bounce a copy
767207141Sjeff		 * of this frame to him:
768207141Sjeff		 */
769207141Sjeff		BPF_MTAP(ifp, m);
770207141Sjeff
771207141Sjeff		m_freem(m);
772207141Sjeff
773207141Sjeff		usbd_transfer_submit(xfer);
774207141Sjeff
775207141Sjeff		return;
776207141Sjeff
777207141Sjeff	default:			/* Error */
778207141Sjeff		DPRINTFN(11, "transfer error, %s\n",
779207141Sjeff		    usbd_errstr(error));
780207141Sjeff
781207141Sjeff		ifp->if_oerrors++;
782207141Sjeff
7831541Srgrimes		if (error != USB_ERR_CANCELLED) {
7841541Srgrimes			/* try to clear stall first */
7852176Spaul			usbd_xfer_set_stall(xfer);
786243245Strasz			goto tr_setup;
787243245Strasz		}
788243245Strasz		return;
789243245Strasz	}
790243245Strasz}
791243245Strasz
7922176Spaulstatic void
793rue_tick(struct usb_ether *ue)
794{
795	struct rue_softc *sc = uether_getsc(ue);
796	struct mii_data *mii = GET_MII(sc);
797
798	RUE_LOCK_ASSERT(sc, MA_OWNED);
799
800	mii_tick(mii);
801	if ((sc->sc_flags & RUE_FLAG_LINK) == 0
802	    && mii->mii_media_status & IFM_ACTIVE &&
803	    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
804		sc->sc_flags |= RUE_FLAG_LINK;
805		rue_start(ue);
806	}
807}
808
809static void
810rue_start(struct usb_ether *ue)
811{
812	struct rue_softc *sc = uether_getsc(ue);
813
814	/*
815	 * start the USB transfers, if not already started:
816	 */
817	usbd_transfer_start(sc->sc_xfer[RUE_INTR_DT_RD]);
818	usbd_transfer_start(sc->sc_xfer[RUE_BULK_DT_RD]);
819	usbd_transfer_start(sc->sc_xfer[RUE_BULK_DT_WR]);
820}
821
822static void
823rue_init(struct usb_ether *ue)
824{
825	struct rue_softc *sc = uether_getsc(ue);
826	struct ifnet *ifp = uether_getifp(ue);
827
828	RUE_LOCK_ASSERT(sc, MA_OWNED);
829
830	/*
831	 * Cancel pending I/O
832	 */
833	rue_reset(sc);
834
835	/* Set MAC address */
836	rue_write_mem(sc, RUE_IDR0, IF_LLADDR(ifp), ETHER_ADDR_LEN);
837
838	rue_stop(ue);
839
840	/*
841	 * Set the initial TX and RX configuration.
842	 */
843	rue_csr_write_1(sc, RUE_TCR, RUE_TCR_CONFIG);
844	rue_csr_write_2(sc, RUE_RCR, RUE_RCR_CONFIG|RUE_RCR_AB);
845
846	/* Load the multicast filter */
847	rue_setpromisc(ue);
848	/* Load the multicast filter. */
849	rue_setmulti(ue);
850
851	/* Enable RX and TX */
852	rue_csr_write_1(sc, RUE_CR, (RUE_CR_TE | RUE_CR_RE | RUE_CR_EP3CLREN));
853
854	usbd_xfer_set_stall(sc->sc_xfer[RUE_BULK_DT_WR]);
855
856	ifp->if_drv_flags |= IFF_DRV_RUNNING;
857	rue_start(ue);
858}
859
860/*
861 * Set media options.
862 */
863static int
864rue_ifmedia_upd(struct ifnet *ifp)
865{
866	struct rue_softc *sc = ifp->if_softc;
867	struct mii_data *mii = GET_MII(sc);
868	struct mii_softc *miisc;
869	int error;
870
871	RUE_LOCK_ASSERT(sc, MA_OWNED);
872
873        sc->sc_flags &= ~RUE_FLAG_LINK;
874	LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
875		PHY_RESET(miisc);
876	error = mii_mediachg(mii);
877	return (error);
878}
879
880/*
881 * Report current media status.
882 */
883static void
884rue_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
885{
886	struct rue_softc *sc = ifp->if_softc;
887	struct mii_data *mii = GET_MII(sc);
888
889	RUE_LOCK(sc);
890	mii_pollstat(mii);
891	ifmr->ifm_active = mii->mii_media_active;
892	ifmr->ifm_status = mii->mii_media_status;
893	RUE_UNLOCK(sc);
894}
895
896static void
897rue_stop(struct usb_ether *ue)
898{
899	struct rue_softc *sc = uether_getsc(ue);
900	struct ifnet *ifp = uether_getifp(ue);
901
902	RUE_LOCK_ASSERT(sc, MA_OWNED);
903
904	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
905	sc->sc_flags &= ~RUE_FLAG_LINK;
906
907	/*
908	 * stop all the transfers, if not already stopped:
909	 */
910	usbd_transfer_stop(sc->sc_xfer[RUE_BULK_DT_WR]);
911	usbd_transfer_stop(sc->sc_xfer[RUE_BULK_DT_RD]);
912	usbd_transfer_stop(sc->sc_xfer[RUE_INTR_DT_RD]);
913
914	rue_csr_write_1(sc, RUE_CR, 0x00);
915
916	rue_reset(sc);
917}
918