if_aue.c revision 212122
1139734Simp/*-
2139734Simp * Copyright (c) 1997, 1998, 1999, 2000
317773Swosch *	Bill Paul <wpaul@ee.columbia.edu>.  All rights reserved.
417773Swosch *
517773Swosch * Copyright (c) 2006
617773Swosch *      Alfred Perlstein <alfred@FreeBSD.org>. All rights reserved.
717773Swosch *
817773Swosch * Redistribution and use in source and binary forms, with or without
917773Swosch * modification, are permitted provided that the following conditions
1017773Swosch * are met:
1117773Swosch * 1. Redistributions of source code must retain the above copyright
1217773Swosch *    notice, this list of conditions and the following disclaimer.
1317773Swosch * 2. Redistributions in binary form must reproduce the above copyright
1417773Swosch *    notice, this list of conditions and the following disclaimer in the
1517773Swosch *    documentation and/or other materials provided with the distribution.
1617773Swosch * 3. All advertising materials mentioning features or use of this software
1717773Swosch *    must display the following acknowledgement:
1817773Swosch *	This product includes software developed by Bill Paul.
1917773Swosch * 4. Neither the name of the author nor the names of any co-contributors
2017773Swosch *    may be used to endorse or promote products derived from this software
2117773Swosch *    without specific prior written permission.
2217773Swosch *
2317773Swosch * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
2417773Swosch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2517773Swosch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26146319Sru * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
27141580Sru * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28141580Sru * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29291754Sngie * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
3012823Sphk * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
3179538Sru * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3212823Sphk * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
3314003Smpp * THE POSSIBILITY OF SUCH DAMAGE.
3475670Sru */
3512823Sphk
3626192Speter#include <sys/cdefs.h>
3768716Sru__FBSDID("$FreeBSD: head/sys/dev/usb/net/if_aue.c 212122 2010-09-01 23:47:53Z thompsa $");
3887529Sru
3987774Simp/*
4087773Simp * ADMtek AN986 Pegasus and AN8511 Pegasus II USB to ethernet driver.
4187773Simp * Datasheet is available from http://www.admtek.com.tw.
4287858Sru *
4387773Simp * Written by Bill Paul <wpaul@ee.columbia.edu>
4471895Sru * Electrical Engineering Department
4512823Sphk * Columbia University, New York City
4675820Sobrien *
4775820Sobrien * SMP locking by Alfred Perlstein <alfred@FreeBSD.org>.
4875820Sobrien * RED Inc.
4975820Sobrien */
5012823Sphk
5112823Sphk/*
5212823Sphk * The Pegasus chip uses four USB "endpoints" to provide 10/100 ethernet
5312823Sphk * support: the control endpoint for reading/writing registers, burst
5412823Sphk * read endpoint for packet reception, burst write for packet transmission
5512823Sphk * and one for "interrupts." The chip uses the same RX filter scheme
5612823Sphk * as the other ADMtek ethernet parts: one perfect filter entry for the
5712823Sphk * the station address and a 64-bit multicast hash table. The chip supports
5812823Sphk * both MII and HomePNA attachments.
5912951Sphk *
6012951Sphk * Since the maximum data transfer speed of USB is supposed to be 12Mbps,
6112823Sphk * you're never really going to get 100Mbps speeds from this device. I
6214966Sjoerg * think the idea is to allow the device to connect to 10 or 100Mbps
6314966Sjoerg * networks, not necessarily to provide 100Mbps performance. Also, since
64139947Skeramida * the controller uses an external PHY chip, it's possible that board
65139725Simp * designers might simply choose a 10Mbps PHY.
66139725Simp *
67139725Simp * Registers are accessed using uether_do_request(). Packet
68166323Sjoel * transfers are done using usbd_transfer() and friends.
69166323Sjoel */
70139725Simp
71175108Sgrog#include <sys/stdint.h>
72139725Simp#include <sys/stddef.h>
73139725Simp#include <sys/param.h>
74139947Skeramida#include <sys/queue.h>
75139734Simp#include <sys/types.h>
76139734Simp#include <sys/systm.h>
77139734Simp#include <sys/kernel.h>
78139734Simp#include <sys/bus.h>
79140173Sru#include <sys/linker_set.h>
80139734Simp#include <sys/module.h>
81139734Simp#include <sys/lock.h>
82139734Simp#include <sys/mutex.h>
83146307Skeramida#include <sys/condvar.h>
84139734Simp#include <sys/sysctl.h>
85139725Simp#include <sys/sx.h>
8675820Sobrien#include <sys/unistd.h>
87146319Sru#include <sys/callout.h>
88146323Sobrien#include <sys/malloc.h>
8975820Sobrien#include <sys/priv.h>
9090018Sbde
9183041Sgrog#include <dev/usb/usb.h>
9283041Sgrog#include <dev/usb/usbdi.h>
9390018Sbde#include <dev/usb/usbdi_util.h>
9483041Sgrog#include "usbdevs.h"
9576708Sobrien
9690042Sobrien#define	USB_DEBUG_VAR aue_debug
9792569Sru#include <dev/usb/usb_debug.h>
9892569Sru#include <dev/usb/usb_process.h>
9990018Sbde
10090018Sbde#include <dev/usb/net/usb_ethernet.h>
10190018Sbde#include <dev/usb/net/if_auereg.h>
10290018Sbde
10390018Sbde#ifdef USB_DEBUG
10490018Sbdestatic int aue_debug = 0;
10590018Sbde
10675820SobrienSYSCTL_NODE(_hw_usb, OID_AUTO, aue, CTLFLAG_RW, 0, "USB aue");
10790018SbdeSYSCTL_INT(_hw_usb_aue, OID_AUTO, debug, CTLFLAG_RW, &aue_debug, 0,
10890018Sbde    "Debug level");
10990018Sbde#endif
110112629Sjhb
11190018Sbde/*
112131132Sbde * Various supported device vendors/products.
11383517Sobrien */
11484307Srustatic const struct usb_device_id aue_devs[] = {
11575820Sobrien#define	AUE_DEV(v,p,i) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) }
11675820Sobrien    AUE_DEV(3COM, 3C460B, AUE_FLAG_PII),
11783041Sgrog    AUE_DEV(ABOCOM, DSB650TX_PNA, 0),
11875820Sobrien    AUE_DEV(ABOCOM, UFE1000, AUE_FLAG_LSYS),
11987529Sru    AUE_DEV(ABOCOM, XX10, 0),
12087529Sru    AUE_DEV(ABOCOM, XX1, AUE_FLAG_PNA | AUE_FLAG_PII),
12187529Sru    AUE_DEV(ABOCOM, XX2, AUE_FLAG_PII),
122119893Sru    AUE_DEV(ABOCOM, XX4, AUE_FLAG_PNA),
12387529Sru    AUE_DEV(ABOCOM, XX5, AUE_FLAG_PNA),
124119893Sru    AUE_DEV(ABOCOM, XX6, AUE_FLAG_PII),
12587529Sru    AUE_DEV(ABOCOM, XX7, AUE_FLAG_PII),
126119893Sru    AUE_DEV(ABOCOM, XX8, AUE_FLAG_PII),
12787529Sru    AUE_DEV(ABOCOM, XX9, AUE_FLAG_PNA),
128119893Sru    AUE_DEV(ACCTON, SS1001, AUE_FLAG_PII),
12987529Sru    AUE_DEV(ACCTON, USB320_EC, 0),
13071895Sru    AUE_DEV(ADMTEK, PEGASUSII_2, AUE_FLAG_PII),
13163324Sben    AUE_DEV(ADMTEK, PEGASUSII_3, AUE_FLAG_PII),
13214966Sjoerg    AUE_DEV(ADMTEK, PEGASUSII_4, AUE_FLAG_PII),
13314966Sjoerg    AUE_DEV(ADMTEK, PEGASUSII, AUE_FLAG_PII),
13483041Sgrog    AUE_DEV(ADMTEK, PEGASUS, AUE_FLAG_PNA | AUE_FLAG_DUAL_PHY),
13571895Sru    AUE_DEV(AEI, FASTETHERNET, AUE_FLAG_PII),
13612823Sphk    AUE_DEV(ALLIEDTELESYN, ATUSB100, AUE_FLAG_PII),
13712823Sphk    AUE_DEV(ATEN, UC110T, AUE_FLAG_PII),
13812823Sphk    AUE_DEV(BELKIN, USB2LAN, AUE_FLAG_PII),
13912823Sphk    AUE_DEV(BILLIONTON, USB100, 0),
14012823Sphk    AUE_DEV(BILLIONTON, USBE100, AUE_FLAG_PII),
14114966Sjoerg    AUE_DEV(BILLIONTON, USBEL100, 0),
14214966Sjoerg    AUE_DEV(BILLIONTON, USBLP100, AUE_FLAG_PNA),
14387773Simp    AUE_DEV(COREGA, FETHER_USB_TXS, AUE_FLAG_PII),
14487773Simp    AUE_DEV(COREGA, FETHER_USB_TX, 0),
14587773Simp    AUE_DEV(DLINK, DSB650TX1, AUE_FLAG_LSYS),
14687773Simp    AUE_DEV(DLINK, DSB650TX2, AUE_FLAG_LSYS | AUE_FLAG_PII),
14787529Sru    AUE_DEV(DLINK, DSB650TX3, AUE_FLAG_LSYS | AUE_FLAG_PII),
148130582Sru    AUE_DEV(DLINK, DSB650TX4, AUE_FLAG_LSYS | AUE_FLAG_PII),
149120530Simp    AUE_DEV(DLINK, DSB650TX_PNA, AUE_FLAG_PNA),
15083041Sgrog    AUE_DEV(DLINK, DSB650TX, AUE_FLAG_LSYS),
15171895Sru    AUE_DEV(DLINK, DSB650, AUE_FLAG_LSYS),
15212823Sphk    AUE_DEV(ELCON, PLAN, AUE_FLAG_PNA | AUE_FLAG_PII),
15314966Sjoerg    AUE_DEV(ELECOM, LDUSB20, AUE_FLAG_PII),
15414966Sjoerg    AUE_DEV(ELECOM, LDUSBLTX, AUE_FLAG_PII),
15587529Sru    AUE_DEV(ELECOM, LDUSBTX0, 0),
156119893Sru    AUE_DEV(ELECOM, LDUSBTX1, AUE_FLAG_LSYS),
15787529Sru    AUE_DEV(ELECOM, LDUSBTX2, 0),
15887529Sru    AUE_DEV(ELECOM, LDUSBTX3, AUE_FLAG_LSYS),
15987529Sru    AUE_DEV(ELSA, USB2ETHERNET, 0),
16087529Sru    AUE_DEV(GIGABYTE, GNBR402W, 0),
16171895Sru    AUE_DEV(HAWKING, UF100, AUE_FLAG_PII),
16212823Sphk    AUE_DEV(HP, HN210E, AUE_FLAG_PII),
16314966Sjoerg    AUE_DEV(IODATA, USBETTXS, AUE_FLAG_PII),
16414966Sjoerg    AUE_DEV(IODATA, USBETTX, 0),
16583041Sgrog    AUE_DEV(KINGSTON, KNU101TX, 0),
16671895Sru    AUE_DEV(LINKSYS, USB100H1, AUE_FLAG_LSYS | AUE_FLAG_PNA),
16712951Sphk    AUE_DEV(LINKSYS, USB100TX, AUE_FLAG_LSYS),
16814966Sjoerg    AUE_DEV(LINKSYS, USB10TA, AUE_FLAG_LSYS),
16914966Sjoerg    AUE_DEV(LINKSYS, USB10TX1, AUE_FLAG_LSYS | AUE_FLAG_PII),
17087529Sru    AUE_DEV(LINKSYS, USB10TX2, AUE_FLAG_LSYS | AUE_FLAG_PII),
17187529Sru    AUE_DEV(LINKSYS, USB10T, AUE_FLAG_LSYS),
17287529Sru    AUE_DEV(MELCO, LUA2TX5, AUE_FLAG_PII),
17364395Ssheldonh    AUE_DEV(MELCO, LUATX1, 0),
17464395Ssheldonh    AUE_DEV(MELCO, LUATX5, 0),
17564395Ssheldonh    AUE_DEV(MICROSOFT, MN110, AUE_FLAG_PII),
17686725Sru    AUE_DEV(NETGEAR, FA101, AUE_FLAG_PII),
17764395Ssheldonh    AUE_DEV(SIEMENS, SPEEDSTREAM, AUE_FLAG_PII),
17864395Ssheldonh    AUE_DEV(SIIG2, USBTOETHER, AUE_FLAG_PII),
17964395Ssheldonh    AUE_DEV(SMARTBRIDGES, SMARTNIC, AUE_FLAG_PII),
18064395Ssheldonh    AUE_DEV(SMC, 2202USB, 0),
18179727Sschweikh    AUE_DEV(SMC, 2206USB, AUE_FLAG_PII),
18287529Sru    AUE_DEV(SOHOWARE, NUB100, 0),
18379727Sschweikh    AUE_DEV(SOHOWARE, NUB110, AUE_FLAG_PII),
18464395Ssheldonh#undef AUE_DEV
18564395Ssheldonh};
18664395Ssheldonh
18764395Ssheldonh/* prototypes */
18864395Ssheldonh
18964395Ssheldonhstatic device_probe_t aue_probe;
19063427Sbenstatic device_attach_t aue_attach;
19149363Shoekstatic device_detach_t aue_detach;
19231613Swollmanstatic miibus_readreg_t aue_miibus_readreg;
19387529Srustatic miibus_writereg_t aue_miibus_writereg;
19431613Swollmanstatic miibus_statchg_t aue_miibus_statchg;
19579727Sschweikh
19687529Srustatic usb_callback_t aue_intr_callback;
19731613Swollmanstatic usb_callback_t aue_bulk_read_callback;
19831614Swollmanstatic usb_callback_t aue_bulk_write_callback;
19931613Swollman
20031613Swollmanstatic uether_fn_t aue_attach_post;
20171895Srustatic uether_fn_t aue_init;
20231613Swollmanstatic uether_fn_t aue_stop;
20312951Sphkstatic uether_fn_t aue_start;
20412951Sphkstatic uether_fn_t aue_tick;
20591436Simpstatic uether_fn_t aue_setmulti;
20614966Sjoergstatic uether_fn_t aue_setpromisc;
20714966Sjoerg
208106302Srwatsonstatic uint8_t	aue_csr_read_1(struct aue_softc *, uint16_t);
209106092Srwatsonstatic uint16_t	aue_csr_read_2(struct aue_softc *, uint16_t);
210106092Srwatsonstatic void	aue_csr_write_1(struct aue_softc *, uint16_t, uint8_t);
211106092Srwatsonstatic void	aue_csr_write_2(struct aue_softc *, uint16_t, uint16_t);
212106092Srwatsonstatic void	aue_eeprom_getword(struct aue_softc *, int, uint16_t *);
213106092Srwatsonstatic void	aue_read_eeprom(struct aue_softc *, uint8_t *, uint16_t,
214106092Srwatson		    uint16_t);
215106092Srwatsonstatic void	aue_reset(struct aue_softc *);
216106302Srwatsonstatic void	aue_reset_pegasus_II(struct aue_softc *);
217106092Srwatson
218106092Srwatsonstatic int	aue_ifmedia_upd(struct ifnet *);
219106092Srwatsonstatic void	aue_ifmedia_sts(struct ifnet *, struct ifmediareq *);
220106092Srwatson
221106092Srwatsonstatic const struct usb_config aue_config[AUE_N_TRANSFER] = {
222106302Srwatson
223107383Sru	[AUE_BULK_DT_WR] = {
224107383Sru		.type = UE_BULK,
225107383Sru		.endpoint = UE_ADDR_ANY,
226106302Srwatson		.direction = UE_DIR_OUT,
227106092Srwatson		.bufsize = (MCLBYTES + 2),
228106092Srwatson		.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
229106092Srwatson		.callback = aue_bulk_write_callback,
230106092Srwatson		.timeout = 10000,	/* 10 seconds */
231106302Srwatson	},
232106092Srwatson
233106092Srwatson	[AUE_BULK_DT_RD] = {
234106092Srwatson		.type = UE_BULK,
235106092Srwatson		.endpoint = UE_ADDR_ANY,
236106302Srwatson		.direction = UE_DIR_IN,
237106092Srwatson		.bufsize = (MCLBYTES + 4 + ETHER_CRC_LEN),
238106092Srwatson		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
239106092Srwatson		.callback = aue_bulk_read_callback,
240106092Srwatson	},
241106092Srwatson
242106302Srwatson	[AUE_INTR_DT_RD] = {
243106302Srwatson		.type = UE_INTERRUPT,
244106302Srwatson		.endpoint = UE_ADDR_ANY,
245106092Srwatson		.direction = UE_DIR_IN,
246106302Srwatson		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
247106302Srwatson		.bufsize = 0,	/* use wMaxPacketSize */
248106302Srwatson		.callback = aue_intr_callback,
249106092Srwatson	},
250106092Srwatson};
251106092Srwatson
252106092Srwatsonstatic device_method_t aue_methods[] = {
253106092Srwatson	/* Device interface */
254106092Srwatson	DEVMETHOD(device_probe, aue_probe),
255106092Srwatson	DEVMETHOD(device_attach, aue_attach),
256106092Srwatson	DEVMETHOD(device_detach, aue_detach),
257106092Srwatson
258106092Srwatson	/* bus interface */
259106092Srwatson	DEVMETHOD(bus_print_child, bus_generic_print_child),
260106092Srwatson	DEVMETHOD(bus_driver_added, bus_generic_driver_added),
261106092Srwatson
262106092Srwatson	/* MII interface */
263106302Srwatson	DEVMETHOD(miibus_readreg, aue_miibus_readreg),
264106092Srwatson	DEVMETHOD(miibus_writereg, aue_miibus_writereg),
265106092Srwatson	DEVMETHOD(miibus_statchg, aue_miibus_statchg),
266106092Srwatson
267106092Srwatson	{0, 0}
268106092Srwatson};
269106302Srwatson
270106092Srwatsonstatic driver_t aue_driver = {
271106092Srwatson	.name = "aue",
272130432Sle	.methods = aue_methods,
273106092Srwatson	.size = sizeof(struct aue_softc)
274106092Srwatson};
275130582Sru
276130582Srustatic devclass_t aue_devclass;
277120530Simp
278130582SruDRIVER_MODULE(aue, uhub, aue_driver, aue_devclass, NULL, 0);
279130582SruDRIVER_MODULE(miibus, aue, miibus_driver, miibus_devclass, 0, 0);
280130582SruMODULE_DEPEND(aue, uether, 1, 1, 1);
281130582SruMODULE_DEPEND(aue, usb, 1, 1, 1);
282130582SruMODULE_DEPEND(aue, ether, 1, 1, 1);
283120530SimpMODULE_DEPEND(aue, miibus, 1, 1, 1);
284120530SimpMODULE_VERSION(aue, 1);
285130582Sru
286130582Srustatic const struct usb_ether_methods aue_ue_methods = {
287120530Simp	.ue_attach_post = aue_attach_post,
288130582Sru	.ue_start = aue_start,
289120530Simp	.ue_init = aue_init,
290120530Simp	.ue_stop = aue_stop,
29131613Swollman	.ue_tick = aue_tick,
29271895Sru	.ue_setmulti = aue_setmulti,
29312823Sphk	.ue_setpromisc = aue_setpromisc,
29414966Sjoerg	.ue_mii_upd = aue_ifmedia_upd,
29514966Sjoerg	.ue_mii_sts = aue_ifmedia_sts,
296209546Scperciva};
297209546Scperciva
298209546Scperciva#define	AUE_SETBIT(sc, reg, x) \
299103189Srobert	aue_csr_write_1(sc, reg, aue_csr_read_1(sc, reg) | (x))
300103189Srobert
301107383Sru#define	AUE_CLRBIT(sc, reg, x) \
302107383Sru	aue_csr_write_1(sc, reg, aue_csr_read_1(sc, reg) & ~(x))
303107383Sru
304107383Srustatic uint8_t
305107383Sruaue_csr_read_1(struct aue_softc *sc, uint16_t reg)
306108317Sschweikh{
307103189Srobert	struct usb_device_request req;
30814966Sjoerg	usb_error_t err;
309138327Sdds	uint8_t val;
31087529Sru
31187529Sru	req.bmRequestType = UT_READ_VENDOR_DEVICE;
31285367Sjulian	req.bRequest = AUE_UR_READREG;
31385445Sjulian	USETW(req.wValue, 0);
31485480Sbde	USETW(req.wIndex, reg);
31599240Simp	USETW(req.wLength, 1);
31699240Simp
31785445Sjulian	err = uether_do_request(&sc->sc_ue, &req, &val, 1000);
31885480Sbde	if (err)
31914966Sjoerg		return (0);
32014966Sjoerg	return (val);
32149363Shoek}
32287529Sru
32387529Srustatic uint16_t
32487529Sruaue_csr_read_2(struct aue_softc *sc, uint16_t reg)
32587529Sru{
32687529Sru	struct usb_device_request req;
32771895Sru	usb_error_t err;
32812823Sphk	uint16_t val;
32985445Sjulian
33085445Sjulian	req.bmRequestType = UT_READ_VENDOR_DEVICE;
33185445Sjulian	req.bRequest = AUE_UR_READREG;
33285445Sjulian	USETW(req.wValue, 0);
33312823Sphk	USETW(req.wIndex, reg);
33485445Sjulian	USETW(req.wLength, 2);
33531612Swollman
33631613Swollman	err = uether_do_request(&sc->sc_ue, &req, &val, 1000);
33731612Swollman	if (err)
33831612Swollman		return (0);
33987529Sru	return (le16toh(val));
34087529Sru}
34131612Swollman
34271895Srustatic void
34331612Swollmanaue_csr_write_1(struct aue_softc *sc, uint16_t reg, uint8_t val)
34487529Sru{
34582952Sobrien	struct usb_device_request req;
34685480Sbde
34785445Sjulian	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
34885445Sjulian	req.bRequest = AUE_UR_WRITEREG;
34985445Sjulian	req.wValue[0] = val;
35031612Swollman	req.wValue[1] = 0;
35185445Sjulian	USETW(req.wIndex, reg);
35231612Swollman	USETW(req.wLength, 1);
35331612Swollman
35487529Sru	if (uether_do_request(&sc->sc_ue, &req, &val, 1000)) {
355122424Sfanf		/* error ignored */
356122424Sfanf	}
357122424Sfanf}
358122424Sfanf
359122424Sfanfstatic void
360122424Sfanfaue_csr_write_2(struct aue_softc *sc, uint16_t reg, uint16_t val)
361122424Sfanf{
362122554Sfanf	struct usb_device_request req;
363122424Sfanf
364122424Sfanf	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
365122424Sfanf	req.bRequest = AUE_UR_WRITEREG;
366122424Sfanf	USETW(req.wValue, val);
36787529Sru	USETW(req.wIndex, reg);
36887529Sru	USETW(req.wLength, 2);
36987529Sru
37087529Sru	val = htole16(val);
37187529Sru
372107282Sru	if (uether_do_request(&sc->sc_ue, &req, &val, 1000)) {
373107282Sru		/* error ignored */
37471895Sru	}
37512823Sphk}
37687569Sobrien
37712951Sphk/*
37812823Sphk * Read a word of data stored in the EEPROM at address 'addr.'
37987569Sobrien */
38087569Sobrienstatic void
38114966Sjoergaue_eeprom_getword(struct aue_softc *sc, int addr, uint16_t *dest)
38214966Sjoerg{
38314966Sjoerg	int i;
38414966Sjoerg	uint16_t word = 0;
385131530Sru
38687529Sru	aue_csr_write_1(sc, AUE_EE_REG, addr);
38787529Sru	aue_csr_write_1(sc, AUE_EE_CTL, AUE_EECTL_READ);
38814966Sjoerg
38987529Sru	for (i = 0; i != AUE_TIMEOUT; i++) {
39014966Sjoerg		if (aue_csr_read_1(sc, AUE_EE_CTL) & AUE_EECTL_DONE)
39114966Sjoerg			break;
39214966Sjoerg		if (uether_pause(&sc->sc_ue, hz / 100))
393102212Simp			break;
394103011Srobert	}
395102212Simp
39614966Sjoerg	if (i == AUE_TIMEOUT)
39714966Sjoerg		device_printf(sc->sc_ue.ue_dev, "EEPROM read timed out\n");
39881449Sru
39987529Sru	word = aue_csr_read_2(sc, AUE_EE_DATA);
40014966Sjoerg	*dest = word;
40190043Simp}
40287529Sru
40390043Simp/*
40414966Sjoerg * Read a sequence of words from the EEPROM.
40526192Speter */
40687529Srustatic void
40787529Sruaue_read_eeprom(struct aue_softc *sc, uint8_t *dest,
40887529Sru    uint16_t off, uint16_t len)
40987529Sru{
41087529Sru	uint16_t *ptr = (uint16_t *)dest;
41187529Sru	int i;
41226192Speter
41326192Speter	for (i = 0; i != len; i++, ptr++)
41414966Sjoerg		aue_eeprom_getword(sc, off + i, ptr);
41571895Sru}
41626192Speter
41714966Sjoergstatic int
41814966Sjoergaue_miibus_readreg(device_t dev, int phy, int reg)
41949363Shoek{
42084408Sobrien	struct aue_softc *sc = device_get_softc(dev);
42186725Sru	int i, locked;
42287529Sru	uint16_t val = 0;
42387529Sru
42484408Sobrien	locked = mtx_owned(&sc->sc_mtx);
42581449Sru	if (!locked)
42671895Sru		AUE_LOCK(sc);
42726192Speter
42826192Speter	/*
42926192Speter	 * The Am79C901 HomePNA PHY actually contains two transceivers: a 1Mbps
43026192Speter	 * HomePNA PHY and a 10Mbps full/half duplex ethernet PHY with NWAY
43171895Sru	 * autoneg. However in the ADMtek adapter, only the 1Mbps PHY is
43226192Speter	 * actually connected to anything, so we ignore the 10Mbps one. It
43326192Speter	 * happens to be configured for MII address 3, so we filter that out.
43426192Speter	 */
43526192Speter	if (sc->sc_flags & AUE_FLAG_DUAL_PHY) {
43626192Speter		if (phy == 3)
43771895Sru			goto done;
43826192Speter#if 0
43975819Sobrien		if (phy != 1)
44026192Speter			goto done;
44112951Sphk#endif
44212823Sphk	}
44312823Sphk	aue_csr_write_1(sc, AUE_PHY_ADDR, phy);
44412823Sphk	aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_READ);
44512823Sphk
44612823Sphk	for (i = 0; i != AUE_TIMEOUT; i++) {
44712823Sphk		if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE)
44826192Speter			break;
44912823Sphk		if (uether_pause(&sc->sc_ue, hz / 100))
45093107Sobrien			break;
45112951Sphk	}
45212951Sphk
45314966Sjoerg	if (i == AUE_TIMEOUT)
45414966Sjoerg		device_printf(sc->sc_ue.ue_dev, "MII read timed out\n");
45587529Sru
45687529Sru	val = aue_csr_read_2(sc, AUE_PHY_DATA);
45787529Sru
45887529Srudone:
45987529Sru	if (!locked)
46087529Sru		AUE_UNLOCK(sc);
46187529Sru	return (val);
46287529Sru}
46387529Sru
46487529Srustatic int
46587529Sruaue_miibus_writereg(device_t dev, int phy, int reg, int data)
46687529Sru{
46787529Sru	struct aue_softc *sc = device_get_softc(dev);
46887529Sru	int i;
46987529Sru	int locked;
47087529Sru
47187529Sru	if (phy == 3)
47287529Sru		return (0);
473217087Strasz
474217087Strasz	locked = mtx_owned(&sc->sc_mtx);
475217087Strasz	if (!locked)
47671895Sru		AUE_LOCK(sc);
477131127Sobrien
47812951Sphk	aue_csr_write_2(sc, AUE_PHY_DATA, data);
47912951Sphk	aue_csr_write_1(sc, AUE_PHY_ADDR, phy);
480164639Sobrien	aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_WRITE);
48112951Sphk
48212951Sphk	for (i = 0; i != AUE_TIMEOUT; i++) {
48312951Sphk		if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE)
48412951Sphk			break;
485131127Sobrien		if (uether_pause(&sc->sc_ue, hz / 100))
486131127Sobrien			break;
487131127Sobrien	}
48812951Sphk
48912951Sphk	if (i == AUE_TIMEOUT)
49049361Shoek		device_printf(sc->sc_ue.ue_dev, "MII write timed out\n");
49149361Shoek
49249361Shoek	if (!locked)
49349361Shoek		AUE_UNLOCK(sc);
49449361Shoek	return (0);
49512951Sphk}
49617812Swosch
49712951Sphkstatic void
49812951Sphkaue_miibus_statchg(device_t dev)
49912951Sphk{
50012951Sphk	struct aue_softc *sc = device_get_softc(dev);
50112951Sphk	struct mii_data *mii = GET_MII(sc);
50214966Sjoerg	int locked;
50314966Sjoerg
50487529Sru	locked = mtx_owned(&sc->sc_mtx);
50587529Sru	if (!locked)
506291754Sngie		AUE_LOCK(sc);
507103179Sfanf
508103179Sfanf	AUE_CLRBIT(sc, AUE_CTL0, AUE_CTL0_RX_ENB | AUE_CTL0_TX_ENB);
509103179Sfanf	if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX)
510291754Sngie		AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_SPEEDSEL);
511291754Sngie	else
512291754Sngie		AUE_CLRBIT(sc, AUE_CTL1, AUE_CTL1_SPEEDSEL);
513291754Sngie
51487529Sru	if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX)
51587529Sru		AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_DUPLEX);
51687529Sru	else
51787529Sru		AUE_CLRBIT(sc, AUE_CTL1, AUE_CTL1_DUPLEX);
51871895Sru
51926192Speter	AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_RX_ENB | AUE_CTL0_TX_ENB);
52026192Speter
52112951Sphk	/*
52212951Sphk	 * Set the LED modes on the LinkSys adapter.
52343406Sjulian	 * This turns on the 'dual link LED' bin in the auxmode
52443406Sjulian	 * register of the Broadcom PHY.
52594682Sasmodai	 */
52643406Sjulian	if (sc->sc_flags & AUE_FLAG_LSYS) {
52743406Sjulian		uint16_t auxmode;
52843406Sjulian
52943406Sjulian		auxmode = aue_miibus_readreg(dev, 0, 0x1b);
53043406Sjulian		aue_miibus_writereg(dev, 0, 0x1b, auxmode | 0x04);
53143406Sjulian	}
53226192Speter	if (!locked)
53326192Speter		AUE_UNLOCK(sc);
53414966Sjoerg}
53514966Sjoerg
53687529Sru#define	AUE_BITS	6
53787529Srustatic void
53887529Sruaue_setmulti(struct usb_ether *ue)
53987529Sru{
54014966Sjoerg	struct aue_softc *sc = uether_getsc(ue);
54171895Sru	struct ifnet *ifp = uether_getifp(ue);
54212951Sphk	struct ifmultiaddr *ifma;
54312951Sphk	uint32_t h = 0;
54412951Sphk	uint32_t i;
54512951Sphk	uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
54614966Sjoerg
54714966Sjoerg	AUE_LOCK_ASSERT(sc, MA_OWNED);
54826192Speter
54914966Sjoerg	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
55080139Sdd		AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI);
55180139Sdd		return;
55271895Sru	}
55394682Sasmodai
55480139Sdd	AUE_CLRBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI);
55515095Smpp
55694682Sasmodai	/* now program new ones */
55778432Sdd	if_maddr_rlock(ifp);
55814966Sjoerg	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
55914966Sjoerg		if (ifma->ifma_addr->sa_family != AF_LINK)
56049363Shoek			continue;
56149363Shoek		h = ether_crc32_le(LLADDR((struct sockaddr_dl *)
56287529Sru		    ifma->ifma_addr), ETHER_ADDR_LEN) & ((1 << AUE_BITS) - 1);
56387529Sru		hashtbl[(h >> 3)] |=  1 << (h & 0x7);
56426192Speter	}
56526192Speter	if_maddr_runlock(ifp);
56687529Sru
56787529Sru	/* write the hashtable */
56887529Sru	for (i = 0; i != 8; i++)
56971895Sru		aue_csr_write_1(sc, AUE_MAR0 + i, hashtbl[i]);
57012951Sphk}
57112951Sphk
57212951Sphkstatic void
57312951Sphkaue_reset_pegasus_II(struct aue_softc *sc)
57412951Sphk{
57512951Sphk	/* Magic constants taken from Linux driver. */
57612951Sphk	aue_csr_write_1(sc, AUE_REG_1D, 0);
57714966Sjoerg	aue_csr_write_1(sc, AUE_REG_7B, 2);
57814966Sjoerg#if 0
57987529Sru	if ((sc->sc_flags & HAS_HOME_PNA) && mii_mode)
58087529Sru		aue_csr_write_1(sc, AUE_REG_81, 6);
58187529Sru	else
58226192Speter#endif
58387529Sru		aue_csr_write_1(sc, AUE_REG_81, 2);
58426192Speter}
58587529Sru
58626192Speterstatic void
58787529Sruaue_reset(struct aue_softc *sc)
58826192Speter{
58987529Sru	int i;
59026192Speter
59171895Sru	AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_RESETMAC);
59272810Sben
59372810Sben	for (i = 0; i != AUE_TIMEOUT; i++) {
59412951Sphk		if (!(aue_csr_read_1(sc, AUE_CTL1) & AUE_CTL1_RESETMAC))
59514966Sjoerg			break;
59614966Sjoerg		if (uether_pause(&sc->sc_ue, hz / 100))
59787529Sru			break;
59887529Sru	}
59987529Sru
60087529Sru	if (i == AUE_TIMEOUT)
60187529Sru		device_printf(sc->sc_ue.ue_dev, "reset failed\n");
60287529Sru
60371895Sru	/*
60412951Sphk	 * The PHY(s) attached to the Pegasus chip may be held
60512951Sphk	 * in reset until we flip on the GPIO outputs. Make sure
60614966Sjoerg	 * to set the GPIO pins high so that the PHY(s) will
60714966Sjoerg	 * be enabled.
608186224Sdes	 *
60971895Sru	 * NOTE: We used to force all of the GPIO pins low first and then
610186224Sdes	 * enable the ones we want. This has been changed to better
61114966Sjoerg	 * match the ADMtek's reference design to avoid setting the
61214966Sjoerg	 * power-down configuration line of the PHY at the same time
61314966Sjoerg	 * it is reset.
61412823Sphk	 */
61514966Sjoerg	aue_csr_write_1(sc, AUE_GPIO0, AUE_GPIO_SEL0|AUE_GPIO_SEL1);
61614966Sjoerg	aue_csr_write_1(sc, AUE_GPIO0, AUE_GPIO_SEL0|AUE_GPIO_SEL1|AUE_GPIO_OUT0);
61714966Sjoerg
61815095Smpp	if (sc->sc_flags & AUE_FLAG_LSYS) {
61988545Salfred		/* Grrr. LinkSys has to be different from everyone else. */
62088545Salfred		aue_csr_write_1(sc, AUE_GPIO0, AUE_GPIO_SEL0|AUE_GPIO_SEL1);
62171895Sru		aue_csr_write_1(sc, AUE_GPIO0,
62212823Sphk		    AUE_GPIO_SEL0|AUE_GPIO_SEL1|AUE_GPIO_OUT0);
62326192Speter	}
62412823Sphk	if (sc->sc_flags & AUE_FLAG_PII)
62514966Sjoerg		aue_reset_pegasus_II(sc);
62614966Sjoerg
62714966Sjoerg	/* Wait a little while for the chip to get its brains in order: */
62814966Sjoerg	uether_pause(&sc->sc_ue, hz / 100);
62971917Snik}
63014966Sjoerg
63114966Sjoergstatic void
63287529Sruaue_attach_post(struct usb_ether *ue)
63387529Sru{
63483041Sgrog	struct aue_softc *sc = uether_getsc(ue);
63571895Sru
63626192Speter	/* reset the adapter */
63726192Speter	aue_reset(sc);
63826192Speter
63926192Speter	/* get station address from the EEPROM */
64026192Speter	aue_read_eeprom(sc, ue->ue_eaddr, 0, 3);
64126192Speter}
64214966Sjoerg
64314966Sjoerg/*
644180424Sdanger * Probe for a Pegasus chip.
645180424Sdanger */
646180424Sdangerstatic int
647180424Sdangeraue_probe(device_t dev)
648180424Sdanger{
64917196Sbde	struct usb_attach_arg *uaa = device_get_ivars(dev);
65087529Sru
65187529Sru	if (uaa->usb_mode != USB_MODE_HOST)
65287529Sru		return (ENXIO);
65387529Sru	if (uaa->info.bConfigIndex != AUE_CONFIG_INDEX)
65426192Speter		return (ENXIO);
65526192Speter	if (uaa->info.bIfaceIndex != AUE_IFACE_IDX)
656100649Simp		return (ENXIO);
657100649Simp	/*
658100649Simp	 * Belkin USB Bluetooth dongles of the F8T012xx1 model series conflict
659101819Sru	 * with older Belkin USB2LAN adapters.  Skip if_aue if we detect one of
660100649Simp	 * the devices that look like Bluetooth adapters.
66126192Speter	 */
66287529Sru	if (uaa->info.idVendor == USB_VENDOR_BELKIN &&
66387529Sru	    uaa->info.idProduct == USB_PRODUCT_BELKIN_F8T012 &&
66487529Sru	    uaa->info.bcdDevice == 0x0413)
66587529Sru		return (ENXIO);
66687529Sru
66787529Sru	return (usbd_lookup_id_by_uaa(aue_devs, sizeof(aue_devs), uaa));
66887529Sru}
66987529Sru
67087529Sru/*
67187529Sru * Attach the interface. Allocate softc structures, do ifmedia
67287529Sru * setup and ethernet/BPF attach.
67387529Sru */
67487529Srustatic int
67587529Sruaue_attach(device_t dev)
67687529Sru{
67749363Shoek	struct usb_attach_arg *uaa = device_get_ivars(dev);
67826192Speter	struct aue_softc *sc = device_get_softc(dev);
67987529Sru	struct usb_ether *ue = &sc->sc_ue;
68087529Sru	uint8_t iface_index;
68187529Sru	int error;
68271895Sru
68352085Scpiazza	sc->sc_flags = USB_GET_DRIVER_INFO(uaa);
68414966Sjoerg
68514966Sjoerg	if (uaa->info.bcdDevice >= 0x0201) {
68614966Sjoerg		/* XXX currently undocumented */
68771895Sru		sc->sc_flags |= AUE_FLAG_VER_2;
68814966Sjoerg	}
68914966Sjoerg
69014966Sjoerg	device_set_usb_desc(dev);
69187529Sru	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
69287529Sru
693140873Sru	iface_index = AUE_IFACE_IDX;
69471895Sru	error = usbd_transfer_setup(uaa->device, &iface_index,
69514966Sjoerg	    sc->sc_xfer, aue_config, AUE_N_TRANSFER,
69614966Sjoerg	    sc, &sc->sc_mtx);
69714966Sjoerg	if (error) {
698140873Sru		device_printf(dev, "allocating USB transfers failed\n");
69971895Sru		goto detach;
70014966Sjoerg	}
70114966Sjoerg
70214966Sjoerg	ue->ue_sc = sc;
70387529Sru	ue->ue_dev = dev;
70487529Sru	ue->ue_udev = uaa->device;
70587529Sru	ue->ue_mtx = &sc->sc_mtx;
70614966Sjoerg	ue->ue_methods = &aue_ue_methods;
70714966Sjoerg
70887529Sru	error = uether_ifattach(ue);
70987529Sru	if (error) {
71087529Sru		device_printf(dev, "could not attach interface\n");
71187486Simp		goto detach;
71214966Sjoerg	}
71315082Smpp	return (0);			/* success */
71415082Smpp
71515082Smppdetach:
71687529Sru	aue_detach(dev);
71771895Sru	return (ENXIO);			/* failure */
71812951Sphk}
719185362Srwatson
72012951Sphkstatic int
721185362Srwatsonaue_detach(device_t dev)
72212951Sphk{
72312823Sphk	struct aue_softc *sc = device_get_softc(dev);
72414966Sjoerg	struct usb_ether *ue = &sc->sc_ue;
72514966Sjoerg
72626192Speter	usbd_transfer_unsetup(sc->sc_xfer, AUE_N_TRANSFER);
72771895Sru	uether_ifdetach(ue);
72826192Speter	mtx_destroy(&sc->sc_mtx);
72926192Speter
73026192Speter	return (0);
73126192Speter}
73226192Speter
73312823Sphkstatic void
73414966Sjoergaue_intr_callback(struct usb_xfer *xfer, usb_error_t error)
73514966Sjoerg{
73648264Smpp	struct aue_softc *sc = usbd_xfer_softc(xfer);
73775819Sobrien	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
73826192Speter	struct aue_intrpkt pkt;
739140873Sru	struct usb_page_cache *pc;
74071895Sru	int actlen;
74112823Sphk
74212823Sphk	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
74312823Sphk
74412823Sphk	switch (USB_GET_STATE(xfer)) {
74512823Sphk	case USB_ST_TRANSFERRED:
74612951Sphk
74726192Speter		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) &&
74812951Sphk		    actlen >= sizeof(pkt)) {
74912951Sphk
75026192Speter			pc = usbd_xfer_get_frame(xfer, 0);
75126192Speter			usbd_copy_out(pc, 0, &pkt, sizeof(pkt));
75212823Sphk
75312823Sphk			if (pkt.aue_txstat0)
75412823Sphk				ifp->if_oerrors++;
75512823Sphk			if (pkt.aue_txstat0 & (AUE_TXSTAT0_LATECOLL &
75614966Sjoerg			    AUE_TXSTAT0_EXCESSCOLL))
75714966Sjoerg				ifp->if_collisions++;
75814966Sjoerg		}
75914966Sjoerg		/* FALLTHROUGH */
76014966Sjoerg	case USB_ST_SETUP:
76114966Sjoergtr_setup:
76287529Sru		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
76387529Sru		usbd_transfer_submit(xfer);
76487529Sru		return;
76587529Sru
76687529Sru	default:			/* Error */
76714966Sjoerg		if (error != USB_ERR_CANCELLED) {
76814966Sjoerg			/* try to clear stall first */
76987529Sru			usbd_xfer_set_stall(xfer);
77087529Sru			goto tr_setup;
77163279Sben		}
77270466Sru		return;
77363279Sben	}
77463279Sben}
77563279Sben
77663427Sbenstatic void
77787529Sruaue_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
77863427Sben{
77987529Sru	struct aue_softc *sc = usbd_xfer_softc(xfer);
78063279Sben	struct usb_ether *ue = &sc->sc_ue;
78163279Sben	struct ifnet *ifp = uether_getifp(ue);
78263279Sben	struct aue_rxpkt stat;
78363279Sben	struct usb_page_cache *pc;
78463279Sben	int actlen;
78563279Sben
78681248Sru	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
78763279Sben	pc = usbd_xfer_get_frame(xfer, 0);
78887529Sru
78963279Sben	switch (USB_GET_STATE(xfer)) {
79063279Sben	case USB_ST_TRANSFERRED:
79163279Sben		DPRINTFN(11, "received %d bytes\n", actlen);
79263279Sben
79363279Sben		if (sc->sc_flags & AUE_FLAG_VER_2) {
79463279Sben
79563279Sben			if (actlen == 0) {
79663279Sben				ifp->if_ierrors++;
79787529Sru				goto tr_setup;
79887529Sru			}
79987529Sru		} else {
80087529Sru
80114966Sjoerg			if (actlen <= sizeof(stat) + ETHER_CRC_LEN) {
80263279Sben				ifp->if_ierrors++;
80387529Sru				goto tr_setup;
80454676Sobrien			}
80554676Sobrien			usbd_copy_out(pc, actlen - sizeof(stat), &stat,
80614966Sjoerg			    sizeof(stat));
80771895Sru
80812951Sphk			/*
809186224Sdes			 * turn off all the non-error bits in the rx status
81012823Sphk			 * word:
81112823Sphk			 */
81214966Sjoerg			stat.aue_rxstat &= AUE_RXSTAT_MASK;
81379982Sobrien			if (stat.aue_rxstat) {
81479982Sobrien				ifp->if_ierrors++;
81581248Sru				goto tr_setup;
81679982Sobrien			}
81779982Sobrien			/* No errors; receive the packet. */
81879982Sobrien			actlen -= (sizeof(stat) + ETHER_CRC_LEN);
81987529Sru		}
82087529Sru		uether_rxbuf(ue, pc, 0, actlen);
82187529Sru
82226192Speter		/* FALLTHROUGH */
82348264Smpp	case USB_ST_SETUP:
82426192Spetertr_setup:
82526192Speter		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
82687529Sru		usbd_transfer_submit(xfer);
82787529Sru		uether_rxflush(ue);
82881248Sru		return;
82981248Sru
83087529Sru	default:			/* Error */
83156049Speter		DPRINTF("bulk read error, %s\n",
83243406Sjulian		    usbd_errstr(error));
83343406Sjulian
83468681Sdwmalone		if (error != USB_ERR_CANCELLED) {
83568681Sdwmalone			/* try to clear stall first */
83668681Sdwmalone			usbd_xfer_set_stall(xfer);
837291754Sngie			goto tr_setup;
83887529Sru		}
83914966Sjoerg		return;
84026192Speter	}
84168681Sdwmalone}
84214966Sjoerg
843114068Strhodesstatic void
844114068Strhodesaue_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
84512823Sphk{
846147647Shmp	struct aue_softc *sc = usbd_xfer_softc(xfer);
84787529Sru	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
84887529Sru	struct usb_page_cache *pc;
84981622Sru	struct mbuf *m;
85085367Sjulian	uint8_t buf[2];
85126192Speter	int actlen;
85268716Sru
85324091Smpp	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
854175710Sobrien	pc = usbd_xfer_get_frame(xfer, 0);
855175710Sobrien
856175710Sobrien	switch (USB_GET_STATE(xfer)) {
857175710Sobrien	case USB_ST_TRANSFERRED:
858		DPRINTFN(11, "transfer of %d bytes complete\n", actlen);
859		ifp->if_opackets++;
860
861		/* FALLTHROUGH */
862	case USB_ST_SETUP:
863tr_setup:
864		if ((sc->sc_flags & AUE_FLAG_LINK) == 0) {
865			/*
866			 * don't send anything if there is no link !
867			 */
868			return;
869		}
870		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
871
872		if (m == NULL)
873			return;
874		if (m->m_pkthdr.len > MCLBYTES)
875			m->m_pkthdr.len = MCLBYTES;
876		if (sc->sc_flags & AUE_FLAG_VER_2) {
877
878			usbd_xfer_set_frame_len(xfer, 0, m->m_pkthdr.len);
879
880			usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len);
881
882		} else {
883
884			usbd_xfer_set_frame_len(xfer, 0, (m->m_pkthdr.len + 2));
885
886			/*
887		         * The ADMtek documentation says that the
888		         * packet length is supposed to be specified
889		         * in the first two bytes of the transfer,
890		         * however it actually seems to ignore this
891		         * info and base the frame size on the bulk
892		         * transfer length.
893		         */
894			buf[0] = (uint8_t)(m->m_pkthdr.len);
895			buf[1] = (uint8_t)(m->m_pkthdr.len >> 8);
896
897			usbd_copy_in(pc, 0, buf, 2);
898			usbd_m_copy_in(pc, 2, m, 0, m->m_pkthdr.len);
899		}
900
901		/*
902		 * if there's a BPF listener, bounce a copy
903		 * of this frame to him:
904		 */
905		BPF_MTAP(ifp, m);
906
907		m_freem(m);
908
909		usbd_transfer_submit(xfer);
910		return;
911
912	default:			/* Error */
913		DPRINTFN(11, "transfer error, %s\n",
914		    usbd_errstr(error));
915
916		ifp->if_oerrors++;
917
918		if (error != USB_ERR_CANCELLED) {
919			/* try to clear stall first */
920			usbd_xfer_set_stall(xfer);
921			goto tr_setup;
922		}
923		return;
924	}
925}
926
927static void
928aue_tick(struct usb_ether *ue)
929{
930	struct aue_softc *sc = uether_getsc(ue);
931	struct mii_data *mii = GET_MII(sc);
932
933	AUE_LOCK_ASSERT(sc, MA_OWNED);
934
935	mii_tick(mii);
936	if ((sc->sc_flags & AUE_FLAG_LINK) == 0
937	    && mii->mii_media_status & IFM_ACTIVE &&
938	    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
939		sc->sc_flags |= AUE_FLAG_LINK;
940		aue_start(ue);
941	}
942}
943
944static void
945aue_start(struct usb_ether *ue)
946{
947	struct aue_softc *sc = uether_getsc(ue);
948
949	/*
950	 * start the USB transfers, if not already started:
951	 */
952	usbd_transfer_start(sc->sc_xfer[AUE_INTR_DT_RD]);
953	usbd_transfer_start(sc->sc_xfer[AUE_BULK_DT_RD]);
954	usbd_transfer_start(sc->sc_xfer[AUE_BULK_DT_WR]);
955}
956
957static void
958aue_init(struct usb_ether *ue)
959{
960	struct aue_softc *sc = uether_getsc(ue);
961	struct ifnet *ifp = uether_getifp(ue);
962	int i;
963
964	AUE_LOCK_ASSERT(sc, MA_OWNED);
965
966	/*
967	 * Cancel pending I/O
968	 */
969	aue_reset(sc);
970
971	/* Set MAC address */
972	for (i = 0; i != ETHER_ADDR_LEN; i++)
973		aue_csr_write_1(sc, AUE_PAR0 + i, IF_LLADDR(ifp)[i]);
974
975	/* update promiscuous setting */
976	aue_setpromisc(ue);
977
978	/* Load the multicast filter. */
979	aue_setmulti(ue);
980
981	/* Enable RX and TX */
982	aue_csr_write_1(sc, AUE_CTL0, AUE_CTL0_RXSTAT_APPEND | AUE_CTL0_RX_ENB);
983	AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_TX_ENB);
984	AUE_SETBIT(sc, AUE_CTL2, AUE_CTL2_EP3_CLR);
985
986	usbd_xfer_set_stall(sc->sc_xfer[AUE_BULK_DT_WR]);
987
988	ifp->if_drv_flags |= IFF_DRV_RUNNING;
989	aue_start(ue);
990}
991
992static void
993aue_setpromisc(struct usb_ether *ue)
994{
995	struct aue_softc *sc = uether_getsc(ue);
996	struct ifnet *ifp = uether_getifp(ue);
997
998	AUE_LOCK_ASSERT(sc, MA_OWNED);
999
1000	/* if we want promiscuous mode, set the allframes bit: */
1001	if (ifp->if_flags & IFF_PROMISC)
1002		AUE_SETBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC);
1003	else
1004		AUE_CLRBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC);
1005}
1006
1007/*
1008 * Set media options.
1009 */
1010static int
1011aue_ifmedia_upd(struct ifnet *ifp)
1012{
1013	struct aue_softc *sc = ifp->if_softc;
1014	struct mii_data *mii = GET_MII(sc);
1015
1016	AUE_LOCK_ASSERT(sc, MA_OWNED);
1017
1018        sc->sc_flags &= ~AUE_FLAG_LINK;
1019	if (mii->mii_instance) {
1020		struct mii_softc *miisc;
1021
1022		LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
1023			mii_phy_reset(miisc);
1024	}
1025	mii_mediachg(mii);
1026	return (0);
1027}
1028
1029/*
1030 * Report current media status.
1031 */
1032static void
1033aue_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
1034{
1035	struct aue_softc *sc = ifp->if_softc;
1036	struct mii_data *mii = GET_MII(sc);
1037
1038	AUE_LOCK(sc);
1039	mii_pollstat(mii);
1040	AUE_UNLOCK(sc);
1041	ifmr->ifm_active = mii->mii_media_active;
1042	ifmr->ifm_status = mii->mii_media_status;
1043}
1044
1045/*
1046 * Stop the adapter and free any mbufs allocated to the
1047 * RX and TX lists.
1048 */
1049static void
1050aue_stop(struct usb_ether *ue)
1051{
1052	struct aue_softc *sc = uether_getsc(ue);
1053	struct ifnet *ifp = uether_getifp(ue);
1054
1055	AUE_LOCK_ASSERT(sc, MA_OWNED);
1056
1057	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1058	sc->sc_flags &= ~AUE_FLAG_LINK;
1059
1060	/*
1061	 * stop all the transfers, if not already stopped:
1062	 */
1063	usbd_transfer_stop(sc->sc_xfer[AUE_BULK_DT_WR]);
1064	usbd_transfer_stop(sc->sc_xfer[AUE_BULK_DT_RD]);
1065	usbd_transfer_stop(sc->sc_xfer[AUE_INTR_DT_RD]);
1066
1067	aue_csr_write_1(sc, AUE_CTL0, 0);
1068	aue_csr_write_1(sc, AUE_CTL1, 0);
1069	aue_reset(sc);
1070}
1071