if_aue.c revision 192499
1109864Sjeff/*-
2113357Sjeff * Copyright (c) 1997, 1998, 1999, 2000
3109864Sjeff *	Bill Paul <wpaul@ee.columbia.edu>.  All rights reserved.
4109864Sjeff *
5109864Sjeff * Copyright (c) 2006
6109864Sjeff *      Alfred Perlstein <alfred@FreeBSD.org>. All rights reserved.
7109864Sjeff *
8109864Sjeff * Redistribution and use in source and binary forms, with or without
9109864Sjeff * modification, are permitted provided that the following conditions
10109864Sjeff * are met:
11109864Sjeff * 1. Redistributions of source code must retain the above copyright
12109864Sjeff *    notice, this list of conditions and the following disclaimer.
13109864Sjeff * 2. Redistributions in binary form must reproduce the above copyright
14109864Sjeff *    notice, this list of conditions and the following disclaimer in the
15109864Sjeff *    documentation and/or other materials provided with the distribution.
16109864Sjeff * 3. All advertising materials mentioning features or use of this software
17109864Sjeff *    must display the following acknowledgement:
18109864Sjeff *	This product includes software developed by Bill Paul.
19109864Sjeff * 4. Neither the name of the author nor the names of any co-contributors
20109864Sjeff *    may be used to endorse or promote products derived from this software
21109864Sjeff *    without specific prior written permission.
22109864Sjeff *
23109864Sjeff * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
24109864Sjeff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25109864Sjeff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26109864Sjeff * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
27116182Sobrien * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28116182Sobrien * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29116182Sobrien * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30109864Sjeff * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31109864Sjeff * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32109864Sjeff * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33109864Sjeff * THE POSSIBILITY OF SUCH DAMAGE.
34109864Sjeff */
35109864Sjeff
36109864Sjeff#include <sys/cdefs.h>
37112966Sjeff__FBSDID("$FreeBSD: head/sys/dev/usb/net/if_aue.c 192499 2009-05-21 00:04:17Z thompsa $");
38109864Sjeff
39109864Sjeff/*
40109864Sjeff * ADMtek AN986 Pegasus and AN8511 Pegasus II USB to ethernet driver.
41109864Sjeff * Datasheet is available from http://www.admtek.com.tw.
42109864Sjeff *
43109864Sjeff * Written by Bill Paul <wpaul@ee.columbia.edu>
44109864Sjeff * Electrical Engineering Department
45109864Sjeff * Columbia University, New York City
46109864Sjeff *
47109864Sjeff * SMP locking by Alfred Perlstein <alfred@FreeBSD.org>.
48109864Sjeff * RED Inc.
49109864Sjeff */
50109864Sjeff
51109864Sjeff/*
52109864Sjeff * The Pegasus chip uses four USB "endpoints" to provide 10/100 ethernet
53109864Sjeff * support: the control endpoint for reading/writing registers, burst
54113357Sjeff * read endpoint for packet reception, burst write for packet transmission
55113357Sjeff * and one for "interrupts." The chip uses the same RX filter scheme
56109864Sjeff * as the other ADMtek ethernet parts: one perfect filter entry for the
57109864Sjeff * the station address and a 64-bit multicast hash table. The chip supports
58109864Sjeff * both MII and HomePNA attachments.
59109864Sjeff *
60109864Sjeff * Since the maximum data transfer speed of USB is supposed to be 12Mbps,
61109864Sjeff * you're never really going to get 100Mbps speeds from this device. I
62109864Sjeff * think the idea is to allow the device to connect to 10 or 100Mbps
63109864Sjeff * networks, not necessarily to provide 100Mbps performance. Also, since
64113357Sjeff * the controller uses an external PHY chip, it's possible that board
65113357Sjeff * designers might simply choose a 10Mbps PHY.
66113357Sjeff *
67113357Sjeff * Registers are accessed using usb2_ether_do_request(). Packet
68113357Sjeff * transfers are done using usb2_transfer() and friends.
69113357Sjeff */
70113357Sjeff
71113357Sjeff#include "usbdevs.h"
72116365Sjeff#include <dev/usb/usb.h>
73113357Sjeff#include <dev/usb/usb_mfunc.h>
74113357Sjeff#include <dev/usb/usb_error.h>
75111857Sjeff
76113357Sjeff#define	USB_DEBUG_VAR aue_debug
77111857Sjeff
78116069Sjeff#include <dev/usb/usb_core.h>
79116069Sjeff#include <dev/usb/usb_lookup.h>
80116069Sjeff#include <dev/usb/usb_process.h>
81116069Sjeff#include <dev/usb/usb_debug.h>
82116069Sjeff#include <dev/usb/usb_request.h>
83109864Sjeff#include <dev/usb/usb_busdma.h>
84109864Sjeff#include <dev/usb/usb_util.h>
85109864Sjeff
86109864Sjeff#include <dev/usb/net/usb_ethernet.h>
87109864Sjeff#include <dev/usb/net/if_auereg.h>
88109864Sjeff
89109864Sjeff#if USB_DEBUG
90109864Sjeffstatic int aue_debug = 0;
91109864Sjeff
92109864SjeffSYSCTL_NODE(_hw_usb2, OID_AUTO, aue, CTLFLAG_RW, 0, "USB aue");
93109864SjeffSYSCTL_INT(_hw_usb2_aue, OID_AUTO, debug, CTLFLAG_RW, &aue_debug, 0,
94109864Sjeff    "Debug level");
95113357Sjeff#endif
96110260Sjeff
97109864Sjeff/*
98109864Sjeff * Various supported device vendors/products.
99109864Sjeff */
100109864Sjeffstatic const struct usb2_device_id aue_devs[] = {
101109864Sjeff    {USB_VPI(USB_VENDOR_3COM, USB_PRODUCT_3COM_3C460B, AUE_FLAG_PII)},
102109864Sjeff    {USB_VPI(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_DSB650TX_PNA, 0)},
103110260Sjeff    {USB_VPI(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_UFE1000, AUE_FLAG_LSYS)},
104109864Sjeff    {USB_VPI(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX10, 0)},
105109864Sjeff    {USB_VPI(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX1, AUE_FLAG_PNA | AUE_FLAG_PII)},
106110645Sjeff    {USB_VPI(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX2, AUE_FLAG_PII)},
107110645Sjeff    {USB_VPI(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX4, AUE_FLAG_PNA)},
108109864Sjeff    {USB_VPI(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX5, AUE_FLAG_PNA)},
109109864Sjeff    {USB_VPI(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX6, AUE_FLAG_PII)},
110110645Sjeff    {USB_VPI(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX7, AUE_FLAG_PII)},
111109864Sjeff    {USB_VPI(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX8, AUE_FLAG_PII)},
112109864Sjeff    {USB_VPI(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX9, AUE_FLAG_PNA)},
113109864Sjeff    {USB_VPI(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_SS1001, AUE_FLAG_PII)},
114109864Sjeff    {USB_VPI(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_USB320_EC, 0)},
115109864Sjeff    {USB_VPI(USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUSII_2, AUE_FLAG_PII)},
116109864Sjeff    {USB_VPI(USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUSII_3, AUE_FLAG_PII)},
117110267Sjeff    {USB_VPI(USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUSII_4, AUE_FLAG_PII)},
118109864Sjeff    {USB_VPI(USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUSII, AUE_FLAG_PII)},
119109864Sjeff    {USB_VPI(USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUS, AUE_FLAG_PNA | AUE_FLAG_DUAL_PHY)},
120109864Sjeff    {USB_VPI(USB_VENDOR_AEI, USB_PRODUCT_AEI_FASTETHERNET, AUE_FLAG_PII)},
121109864Sjeff    {USB_VPI(USB_VENDOR_ALLIEDTELESYN, USB_PRODUCT_ALLIEDTELESYN_ATUSB100, AUE_FLAG_PII)},
122109864Sjeff    {USB_VPI(USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC110T, AUE_FLAG_PII)},
123109864Sjeff    {USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_USB2LAN, AUE_FLAG_PII)},
124109864Sjeff    {USB_VPI(USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USB100, 0)},
125109864Sjeff    {USB_VPI(USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USBE100, AUE_FLAG_PII)},
126109864Sjeff    {USB_VPI(USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USBEL100, 0)},
127116642Sjeff    {USB_VPI(USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USBLP100, AUE_FLAG_PNA)},
128116642Sjeff    {USB_VPI(USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TXS, AUE_FLAG_PII)},
129116642Sjeff    {USB_VPI(USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TX, 0)},
130116642Sjeff    {USB_VPI(USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX1, AUE_FLAG_LSYS)},
131111857Sjeff    {USB_VPI(USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX2, AUE_FLAG_LSYS | AUE_FLAG_PII)},
132111857Sjeff    {USB_VPI(USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX3, AUE_FLAG_LSYS | AUE_FLAG_PII)},
133116642Sjeff    {USB_VPI(USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX4, AUE_FLAG_LSYS | AUE_FLAG_PII)},
134111857Sjeff    {USB_VPI(USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX_PNA, AUE_FLAG_PNA)},
135109864Sjeff    {USB_VPI(USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX, AUE_FLAG_LSYS)},
136111857Sjeff    {USB_VPI(USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650, AUE_FLAG_LSYS)},
137112966Sjeff    {USB_VPI(USB_VENDOR_ELCON, USB_PRODUCT_ELCON_PLAN, AUE_FLAG_PNA | AUE_FLAG_PII)},
138112970Sjeff    {USB_VPI(USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSB20, AUE_FLAG_PII)},
139113357Sjeff    {USB_VPI(USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBLTX, AUE_FLAG_PII)},
140116642Sjeff    {USB_VPI(USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX0, 0)},
141113357Sjeff    {USB_VPI(USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX1, AUE_FLAG_LSYS)},
142116642Sjeff    {USB_VPI(USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX2, 0)},
143109864Sjeff    {USB_VPI(USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX3, AUE_FLAG_LSYS)},
144109864Sjeff    {USB_VPI(USB_VENDOR_ELSA, USB_PRODUCT_ELSA_USB2ETHERNET, 0)},
145111857Sjeff    {USB_VPI(USB_VENDOR_GIGABYTE, USB_PRODUCT_GIGABYTE_GNBR402W, 0)},
146109864Sjeff    {USB_VPI(USB_VENDOR_HAWKING, USB_PRODUCT_HAWKING_UF100, AUE_FLAG_PII)},
147110645Sjeff    {USB_VPI(USB_VENDOR_HP, USB_PRODUCT_HP_HN210E, AUE_FLAG_PII)},
148110645Sjeff    {USB_VPI(USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBETTXS, AUE_FLAG_PII)},
149116955Sjeff    {USB_VPI(USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBETTX, 0)},
150116365Sjeff    {USB_VPI(USB_VENDOR_KINGSTON, USB_PRODUCT_KINGSTON_KNU101TX, 0)},
151111857Sjeff    {USB_VPI(USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB100H1, AUE_FLAG_LSYS | AUE_FLAG_PNA)},
152109864Sjeff    {USB_VPI(USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB100TX, AUE_FLAG_LSYS)},
153121126Sjeff    {USB_VPI(USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10TA, AUE_FLAG_LSYS)},
154116955Sjeff    {USB_VPI(USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10TX1, AUE_FLAG_LSYS | AUE_FLAG_PII)},
155116365Sjeff    {USB_VPI(USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10TX2, AUE_FLAG_LSYS | AUE_FLAG_PII)},
156116365Sjeff    {USB_VPI(USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10T, AUE_FLAG_LSYS)},
157121126Sjeff    {USB_VPI(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUA2TX5, AUE_FLAG_PII)},
158111857Sjeff    {USB_VPI(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUATX1, 0)},
159109864Sjeff    {USB_VPI(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUATX5, 0)},
160109864Sjeff    {USB_VPI(USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_MN110, AUE_FLAG_PII)},
161109864Sjeff    {USB_VPI(USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_FA101, AUE_FLAG_PII)},
162109864Sjeff    {USB_VPI(USB_VENDOR_SIEMENS, USB_PRODUCT_SIEMENS_SPEEDSTREAM, AUE_FLAG_PII)},
163109864Sjeff    {USB_VPI(USB_VENDOR_SIIG2, USB_PRODUCT_SIIG2_USBTOETHER, AUE_FLAG_PII)},
164109864Sjeff    {USB_VPI(USB_VENDOR_SMARTBRIDGES, USB_PRODUCT_SMARTBRIDGES_SMARTNIC, AUE_FLAG_PII)},
165109864Sjeff    {USB_VPI(USB_VENDOR_SMC, USB_PRODUCT_SMC_2202USB, 0)},
166112966Sjeff    {USB_VPI(USB_VENDOR_SMC, USB_PRODUCT_SMC_2206USB, AUE_FLAG_PII)},
167112966Sjeff    {USB_VPI(USB_VENDOR_SOHOWARE, USB_PRODUCT_SOHOWARE_NUB100, 0)},
168109864Sjeff    {USB_VPI(USB_VENDOR_SOHOWARE, USB_PRODUCT_SOHOWARE_NUB110, AUE_FLAG_PII)},
169113357Sjeff};
170113357Sjeff
171111857Sjeff/* prototypes */
172109864Sjeff
173112966Sjeffstatic device_probe_t aue_probe;
174113357Sjeffstatic device_attach_t aue_attach;
175109864Sjeffstatic device_detach_t aue_detach;
176109864Sjeffstatic miibus_readreg_t aue_miibus_readreg;
177109864Sjeffstatic miibus_writereg_t aue_miibus_writereg;
178109864Sjeffstatic miibus_statchg_t aue_miibus_statchg;
179110645Sjeff
180110645Sjeffstatic usb2_callback_t aue_intr_callback;
181109864Sjeffstatic usb2_callback_t aue_bulk_read_callback;
182113357Sjeffstatic usb2_callback_t aue_bulk_write_callback;
183113357Sjeff
184113417Sjeffstatic usb2_ether_fn_t aue_attach_post;
185121107Sjeffstatic usb2_ether_fn_t aue_init;
186121107Sjeffstatic usb2_ether_fn_t aue_stop;
187109864Sjeffstatic usb2_ether_fn_t aue_start;
188109864Sjeffstatic usb2_ether_fn_t aue_tick;
189109864Sjeffstatic usb2_ether_fn_t aue_setmulti;
190109864Sjeffstatic usb2_ether_fn_t aue_setpromisc;
191109864Sjeff
192109864Sjeffstatic uint8_t	aue_csr_read_1(struct aue_softc *, uint16_t);
193109864Sjeffstatic uint16_t	aue_csr_read_2(struct aue_softc *, uint16_t);
194109864Sjeffstatic void	aue_csr_write_1(struct aue_softc *, uint16_t, uint8_t);
195112971Sjeffstatic void	aue_csr_write_2(struct aue_softc *, uint16_t, uint16_t);
196109864Sjeffstatic void	aue_eeprom_getword(struct aue_softc *, int, uint16_t *);
197109864Sjeffstatic void	aue_read_eeprom(struct aue_softc *, uint8_t *, uint16_t,
198109864Sjeff		    uint16_t);
199113357Sjeffstatic void	aue_reset(struct aue_softc *);
200109864Sjeffstatic void	aue_reset_pegasus_II(struct aue_softc *);
201109864Sjeff
202113357Sjeffstatic int	aue_ifmedia_upd(struct ifnet *);
203113357Sjeffstatic void	aue_ifmedia_sts(struct ifnet *, struct ifmediareq *);
204109864Sjeff
205113357Sjeffstatic const struct usb2_config aue_config[AUE_N_TRANSFER] = {
206113357Sjeff
207113357Sjeff	[AUE_BULK_DT_WR] = {
208113357Sjeff		.type = UE_BULK,
209113357Sjeff		.endpoint = UE_ADDR_ANY,
210113357Sjeff		.direction = UE_DIR_OUT,
211113357Sjeff		.bufsize = (MCLBYTES + 2),
212113357Sjeff		.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
213110267Sjeff		.callback = aue_bulk_write_callback,
214117237Sjeff		.timeout = 10000,	/* 10 seconds */
215110267Sjeff	},
216110267Sjeff
217109864Sjeff	[AUE_BULK_DT_RD] = {
218109864Sjeff		.type = UE_BULK,
219109864Sjeff		.endpoint = UE_ADDR_ANY,
220109864Sjeff		.direction = UE_DIR_IN,
221109864Sjeff		.bufsize = (MCLBYTES + 4 + ETHER_CRC_LEN),
222110028Sjeff		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
223109864Sjeff		.callback = aue_bulk_read_callback,
224117237Sjeff	},
225117237Sjeff
226117237Sjeff	[AUE_INTR_DT_RD] = {
227110028Sjeff		.type = UE_INTERRUPT,
228110028Sjeff		.endpoint = UE_ADDR_ANY,
229110028Sjeff		.direction = UE_DIR_IN,
230110028Sjeff		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
231110028Sjeff		.bufsize = 0,	/* use wMaxPacketSize */
232109864Sjeff		.callback = aue_intr_callback,
233112966Sjeff	},
234113357Sjeff};
235111857Sjeff
236116463Sjeffstatic device_method_t aue_methods[] = {
237109864Sjeff	/* Device interface */
238109864Sjeff	DEVMETHOD(device_probe, aue_probe),
239109864Sjeff	DEVMETHOD(device_attach, aue_attach),
240110267Sjeff	DEVMETHOD(device_detach, aue_detach),
241117326Sjeff
242110028Sjeff	/* bus interface */
243112994Sjeff	DEVMETHOD(bus_print_child, bus_generic_print_child),
244113357Sjeff	DEVMETHOD(bus_driver_added, bus_generic_driver_added),
245113357Sjeff
246113357Sjeff	/* MII interface */
247113660Sjeff	DEVMETHOD(miibus_readreg, aue_miibus_readreg),
248110267Sjeff	DEVMETHOD(miibus_writereg, aue_miibus_writereg),
249110267Sjeff	DEVMETHOD(miibus_statchg, aue_miibus_statchg),
250116069Sjeff
251116069Sjeff	{0, 0}
252110267Sjeff};
253110028Sjeff
254113357Sjeffstatic driver_t aue_driver = {
255113660Sjeff	.name = "aue",
256110267Sjeff	.methods = aue_methods,
257113660Sjeff	.size = sizeof(struct aue_softc)
258113357Sjeff};
259112994Sjeff
260113660Sjeffstatic devclass_t aue_devclass;
261112994Sjeff
262113357SjeffDRIVER_MODULE(aue, uhub, aue_driver, aue_devclass, NULL, 0);
263113357SjeffDRIVER_MODULE(miibus, aue, miibus_driver, miibus_devclass, 0, 0);
264113357SjeffMODULE_DEPEND(aue, uether, 1, 1, 1);
265113357SjeffMODULE_DEPEND(aue, usb, 1, 1, 1);
266113357SjeffMODULE_DEPEND(aue, ether, 1, 1, 1);
267113357SjeffMODULE_DEPEND(aue, miibus, 1, 1, 1);
268113357Sjeff
269113357Sjeffstatic const struct usb2_ether_methods aue_ue_methods = {
270113357Sjeff	.ue_attach_post = aue_attach_post,
271113357Sjeff	.ue_start = aue_start,
272113357Sjeff	.ue_init = aue_init,
273113357Sjeff	.ue_stop = aue_stop,
274113357Sjeff	.ue_tick = aue_tick,
275112994Sjeff	.ue_setmulti = aue_setmulti,
276113357Sjeff	.ue_setpromisc = aue_setpromisc,
277113357Sjeff	.ue_mii_upd = aue_ifmedia_upd,
278113357Sjeff	.ue_mii_sts = aue_ifmedia_sts,
279115998Sjeff};
280113386Sjeff
281113357Sjeff#define	AUE_SETBIT(sc, reg, x) \
282113357Sjeff	aue_csr_write_1(sc, reg, aue_csr_read_1(sc, reg) | (x))
283113357Sjeff
284113357Sjeff#define	AUE_CLRBIT(sc, reg, x) \
285113357Sjeff	aue_csr_write_1(sc, reg, aue_csr_read_1(sc, reg) & ~(x))
286113357Sjeff
287113357Sjeffstatic uint8_t
288110267Sjeffaue_csr_read_1(struct aue_softc *sc, uint16_t reg)
289110267Sjeff{
290110267Sjeff	struct usb2_device_request req;
291110267Sjeff	usb2_error_t err;
292113357Sjeff	uint8_t val;
293112994Sjeff
294110267Sjeff	req.bmRequestType = UT_READ_VENDOR_DEVICE;
295110267Sjeff	req.bRequest = AUE_UR_READREG;
296115998Sjeff	USETW(req.wValue, 0);
297113386Sjeff	USETW(req.wIndex, reg);
298113357Sjeff	USETW(req.wLength, 1);
299113357Sjeff
300113357Sjeff	err = usb2_ether_do_request(&sc->sc_ue, &req, &val, 1000);
301113357Sjeff	if (err)
302110267Sjeff		return (0);
303110267Sjeff	return (val);
304110267Sjeff}
305110267Sjeff
306110267Sjeffstatic uint16_t
307113357Sjeffaue_csr_read_2(struct aue_softc *sc, uint16_t reg)
308113357Sjeff{
309110267Sjeff	struct usb2_device_request req;
310115998Sjeff	usb2_error_t err;
311113357Sjeff	uint16_t val;
312113357Sjeff
313115998Sjeff	req.bmRequestType = UT_READ_VENDOR_DEVICE;
314113357Sjeff	req.bRequest = AUE_UR_READREG;
315110267Sjeff	USETW(req.wValue, 0);
316110267Sjeff	USETW(req.wIndex, reg);
317113357Sjeff	USETW(req.wLength, 2);
318113357Sjeff
319110267Sjeff	err = usb2_ether_do_request(&sc->sc_ue, &req, &val, 1000);
320113357Sjeff	if (err)
321113357Sjeff		return (0);
322115998Sjeff	return (le16toh(val));
323113357Sjeff}
324113357Sjeff
325113357Sjeffstatic void
326113357Sjeffaue_csr_write_1(struct aue_softc *sc, uint16_t reg, uint8_t val)
327113357Sjeff{
328113357Sjeff	struct usb2_device_request req;
329113357Sjeff
330113357Sjeff	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
331113357Sjeff	req.bRequest = AUE_UR_WRITEREG;
332113357Sjeff	req.wValue[0] = val;
333113357Sjeff	req.wValue[1] = 0;
334113357Sjeff	USETW(req.wIndex, reg);
335113357Sjeff	USETW(req.wLength, 1);
336113357Sjeff
337113357Sjeff	if (usb2_ether_do_request(&sc->sc_ue, &req, &val, 1000)) {
338113357Sjeff		/* error ignored */
339113357Sjeff	}
340113357Sjeff}
341113357Sjeff
342113357Sjeffstatic void
343110267Sjeffaue_csr_write_2(struct aue_softc *sc, uint16_t reg, uint16_t val)
344110267Sjeff{
345113357Sjeff	struct usb2_device_request req;
346116069Sjeff
347116069Sjeff	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
348116069Sjeff	req.bRequest = AUE_UR_WRITEREG;
349116069Sjeff	USETW(req.wValue, val);
350116069Sjeff	USETW(req.wIndex, reg);
351116069Sjeff	USETW(req.wLength, 2);
352116069Sjeff
353116069Sjeff	val = htole16(val);
354116069Sjeff
355116069Sjeff	if (usb2_ether_do_request(&sc->sc_ue, &req, &val, 1000)) {
356116069Sjeff		/* error ignored */
357116069Sjeff	}
358116069Sjeff}
359116069Sjeff
360116069Sjeff/*
361116069Sjeff * Read a word of data stored in the EEPROM at address 'addr.'
362116069Sjeff */
363116069Sjeffstatic void
364116069Sjeffaue_eeprom_getword(struct aue_softc *sc, int addr, uint16_t *dest)
365116069Sjeff{
366116069Sjeff	int i;
367116069Sjeff	uint16_t word = 0;
368116069Sjeff
369116069Sjeff	aue_csr_write_1(sc, AUE_EE_REG, addr);
370116069Sjeff	aue_csr_write_1(sc, AUE_EE_CTL, AUE_EECTL_READ);
371116069Sjeff
372116069Sjeff	for (i = 0; i != AUE_TIMEOUT; i++) {
373116069Sjeff		if (aue_csr_read_1(sc, AUE_EE_CTL) & AUE_EECTL_DONE)
374116069Sjeff			break;
375116069Sjeff		if (usb2_ether_pause(&sc->sc_ue, hz / 100))
376116069Sjeff			break;
377116069Sjeff	}
378116069Sjeff
379116069Sjeff	if (i == AUE_TIMEOUT)
380116962Sjeff		device_printf(sc->sc_ue.ue_dev, "EEPROM read timed out\n");
381116962Sjeff
382116962Sjeff	word = aue_csr_read_2(sc, AUE_EE_DATA);
383116069Sjeff	*dest = word;
384116970Sjeff}
385116069Sjeff
386116069Sjeff/*
387116069Sjeff * Read a sequence of words from the EEPROM.
388116069Sjeff */
389116069Sjeffstatic void
390116069Sjeffaue_read_eeprom(struct aue_softc *sc, uint8_t *dest,
391116069Sjeff    uint16_t off, uint16_t len)
392116069Sjeff{
393116069Sjeff	uint16_t *ptr = (uint16_t *)dest;
394116069Sjeff	int i;
395116069Sjeff
396116069Sjeff	for (i = 0; i != len; i++, ptr++)
397117237Sjeff		aue_eeprom_getword(sc, off + i, ptr);
398117237Sjeff}
399116069Sjeff
400116069Sjeffstatic int
401116069Sjeffaue_miibus_readreg(device_t dev, int phy, int reg)
402117237Sjeff{
403116069Sjeff	struct aue_softc *sc = device_get_softc(dev);
404116069Sjeff	int i, locked;
405117237Sjeff	uint16_t val = 0;
406117237Sjeff
407117237Sjeff	locked = mtx_owned(&sc->sc_mtx);
408117237Sjeff	if (!locked)
409117237Sjeff		AUE_LOCK(sc);
410116069Sjeff
411116069Sjeff	/*
412116069Sjeff	 * The Am79C901 HomePNA PHY actually contains two transceivers: a 1Mbps
413116069Sjeff	 * HomePNA PHY and a 10Mbps full/half duplex ethernet PHY with NWAY
414116069Sjeff	 * autoneg. However in the ADMtek adapter, only the 1Mbps PHY is
415116069Sjeff	 * actually connected to anything, so we ignore the 10Mbps one. It
416117237Sjeff	 * happens to be configured for MII address 3, so we filter that out.
417116069Sjeff	 */
418116069Sjeff	if (sc->sc_flags & AUE_FLAG_DUAL_PHY) {
419116069Sjeff		if (phy == 3)
420116069Sjeff			goto done;
421116069Sjeff#if 0
422116069Sjeff		if (phy != 1)
423116069Sjeff			goto done;
424116069Sjeff#endif
425110267Sjeff	}
426110267Sjeff	aue_csr_write_1(sc, AUE_PHY_ADDR, phy);
427110267Sjeff	aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_READ);
428110267Sjeff
429110267Sjeff	for (i = 0; i != AUE_TIMEOUT; i++) {
430110267Sjeff		if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE)
431110267Sjeff			break;
432110267Sjeff		if (usb2_ether_pause(&sc->sc_ue, hz / 100))
433115998Sjeff			break;
434110267Sjeff	}
435110267Sjeff
436110267Sjeff	if (i == AUE_TIMEOUT)
437110267Sjeff		device_printf(sc->sc_ue.ue_dev, "MII read timed out\n");
438116970Sjeff
439110267Sjeff	val = aue_csr_read_2(sc, AUE_PHY_DATA);
440110267Sjeff
441113357Sjeffdone:
442113357Sjeff	if (!locked)
443110267Sjeff		AUE_UNLOCK(sc);
444110267Sjeff	return (val);
445110267Sjeff}
446117237Sjeff
447110267Sjeffstatic int
448117237Sjeffaue_miibus_writereg(device_t dev, int phy, int reg, int data)
449117237Sjeff{
450117237Sjeff	struct aue_softc *sc = device_get_softc(dev);
451110267Sjeff	int i;
452110267Sjeff	int locked;
453116069Sjeff
454116069Sjeff	if (phy == 3)
455116069Sjeff		return (0);
456116069Sjeff
457116069Sjeff	locked = mtx_owned(&sc->sc_mtx);
458116069Sjeff	if (!locked)
459117326Sjeff		AUE_LOCK(sc);
460116069Sjeff
461116069Sjeff	aue_csr_write_2(sc, AUE_PHY_DATA, data);
462116069Sjeff	aue_csr_write_1(sc, AUE_PHY_ADDR, phy);
463116069Sjeff	aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_WRITE);
464116069Sjeff
465121145Sjeff	for (i = 0; i != AUE_TIMEOUT; i++) {
466116069Sjeff		if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE)
467110267Sjeff			break;
468110267Sjeff		if (usb2_ether_pause(&sc->sc_ue, hz / 100))
469117326Sjeff			break;
470117326Sjeff	}
471117326Sjeff
472117326Sjeff	if (i == AUE_TIMEOUT)
473117326Sjeff		device_printf(sc->sc_ue.ue_dev, "MII read timed out\n");
474117326Sjeff
475110267Sjeff	if (!locked)
476117326Sjeff		AUE_UNLOCK(sc);
477110267Sjeff	return (0);
478110267Sjeff}
479110267Sjeff
480110267Sjeffstatic void
481115998Sjeffaue_miibus_statchg(device_t dev)
482113357Sjeff{
483112994Sjeff	struct aue_softc *sc = device_get_softc(dev);
484113357Sjeff	struct mii_data *mii = GET_MII(sc);
485113357Sjeff	int locked;
486113357Sjeff
487113357Sjeff	locked = mtx_owned(&sc->sc_mtx);
488113357Sjeff	if (!locked)
489113357Sjeff		AUE_LOCK(sc);
490113357Sjeff
491113357Sjeff	AUE_CLRBIT(sc, AUE_CTL0, AUE_CTL0_RX_ENB | AUE_CTL0_TX_ENB);
492113357Sjeff	if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX)
493113357Sjeff		AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_SPEEDSEL);
494113357Sjeff	else
495113357Sjeff		AUE_CLRBIT(sc, AUE_CTL1, AUE_CTL1_SPEEDSEL);
496113357Sjeff
497113357Sjeff	if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX)
498113357Sjeff		AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_DUPLEX);
499113357Sjeff	else
500113357Sjeff		AUE_CLRBIT(sc, AUE_CTL1, AUE_CTL1_DUPLEX);
501113357Sjeff
502117326Sjeff	AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_RX_ENB | AUE_CTL0_TX_ENB);
503113357Sjeff
504113357Sjeff	/*
505113357Sjeff	 * Set the LED modes on the LinkSys adapter.
506113357Sjeff	 * This turns on the 'dual link LED' bin in the auxmode
507113357Sjeff	 * register of the Broadcom PHY.
508113357Sjeff	 */
509113357Sjeff	if (sc->sc_flags & AUE_FLAG_LSYS) {
510110267Sjeff		uint16_t auxmode;
511110267Sjeff
512113357Sjeff		auxmode = aue_miibus_readreg(dev, 0, 0x1b);
513110267Sjeff		aue_miibus_writereg(dev, 0, 0x1b, auxmode | 0x04);
514110267Sjeff	}
515109864Sjeff	if (!locked)
516110028Sjeff		AUE_UNLOCK(sc);
517110028Sjeff}
518113357Sjeff
519113357Sjeff#define	AUE_BITS	6
520112994Sjeffstatic void
521113357Sjeffaue_setmulti(struct usb2_ether *ue)
522113357Sjeff{
523113357Sjeff	struct aue_softc *sc = usb2_ether_getsc(ue);
524113357Sjeff	struct ifnet *ifp = usb2_ether_getifp(ue);
525113357Sjeff	struct ifmultiaddr *ifma;
526113357Sjeff	uint32_t h = 0;
527113357Sjeff	uint32_t i;
528113357Sjeff	uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
529113660Sjeff
530110267Sjeff	AUE_LOCK_ASSERT(sc, MA_OWNED);
531110267Sjeff
532110267Sjeff	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
533110028Sjeff		AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI);
534110028Sjeff		return;
535110028Sjeff	}
536109864Sjeff
537109864Sjeff	AUE_CLRBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI);
538117313Sjeff
539109864Sjeff	/* now program new ones */
540117313Sjeff	IF_ADDR_LOCK(ifp);
541109864Sjeff	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
542116946Sjeff		if (ifma->ifma_addr->sa_family != AF_LINK)
543116946Sjeff			continue;
544111857Sjeff		h = ether_crc32_le(LLADDR((struct sockaddr_dl *)
545117237Sjeff		    ifma->ifma_addr), ETHER_ADDR_LEN) & ((1 << AUE_BITS) - 1);
546109864Sjeff		hashtbl[(h >> 3)] |=  1 << (h & 0x7);
547117237Sjeff	}
548117237Sjeff	IF_ADDR_UNLOCK(ifp);
549117237Sjeff
550117237Sjeff	/* write the hashtable */
551117237Sjeff	for (i = 0; i != 8; i++)
552117237Sjeff		aue_csr_write_1(sc, AUE_MAR0 + i, hashtbl[i]);
553117237Sjeff}
554117237Sjeff
555117237Sjeffstatic void
556117237Sjeffaue_reset_pegasus_II(struct aue_softc *sc)
557117237Sjeff{
558117237Sjeff	/* Magic constants taken from Linux driver. */
559117237Sjeff	aue_csr_write_1(sc, AUE_REG_1D, 0);
560113357Sjeff	aue_csr_write_1(sc, AUE_REG_7B, 2);
561117237Sjeff#if 0
562117237Sjeff	if ((sc->sc_flags & HAS_HOME_PNA) && mii_mode)
563117237Sjeff		aue_csr_write_1(sc, AUE_REG_81, 6);
564117237Sjeff	else
565117237Sjeff#endif
566117237Sjeff		aue_csr_write_1(sc, AUE_REG_81, 2);
567117237Sjeff}
568117237Sjeff
569117237Sjeffstatic void
570117237Sjeffaue_reset(struct aue_softc *sc)
571117237Sjeff{
572117237Sjeff	int i;
573119137Ssam
574116069Sjeff	AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_RESETMAC);
575117237Sjeff
576117237Sjeff	for (i = 0; i != AUE_TIMEOUT; i++) {
577116069Sjeff		if (!(aue_csr_read_1(sc, AUE_CTL1) & AUE_CTL1_RESETMAC))
578117237Sjeff			break;
579117237Sjeff		if (usb2_ether_pause(&sc->sc_ue, hz / 100))
580117237Sjeff			break;
581109864Sjeff	}
582109864Sjeff
583109864Sjeff	if (i == AUE_TIMEOUT)
584109864Sjeff		device_printf(sc->sc_ue.ue_dev, "reset failed\n");
585109864Sjeff
586109864Sjeff	/*
587113357Sjeff	 * The PHY(s) attached to the Pegasus chip may be held
588109864Sjeff	 * in reset until we flip on the GPIO outputs. Make sure
589109864Sjeff	 * to set the GPIO pins high so that the PHY(s) will
590109864Sjeff	 * be enabled.
591109864Sjeff	 *
592109864Sjeff	 * Note: We force all of the GPIO pins low first, *then*
593113357Sjeff	 * enable the ones we want.
594109864Sjeff	 */
595113357Sjeff	aue_csr_write_1(sc, AUE_GPIO0, AUE_GPIO_OUT0|AUE_GPIO_SEL0);
596111857Sjeff	aue_csr_write_1(sc, AUE_GPIO0, AUE_GPIO_OUT0|AUE_GPIO_SEL0|AUE_GPIO_SEL1);
597109864Sjeff
598109864Sjeff	if (sc->sc_flags & AUE_FLAG_LSYS) {
599109864Sjeff		/* Grrr. LinkSys has to be different from everyone else. */
600109864Sjeff		aue_csr_write_1(sc, AUE_GPIO0, AUE_GPIO_SEL0|AUE_GPIO_SEL1);
601109864Sjeff		aue_csr_write_1(sc, AUE_GPIO0,
602109864Sjeff		    AUE_GPIO_SEL0|AUE_GPIO_SEL1|AUE_GPIO_OUT0);
603109864Sjeff	}
604109864Sjeff	if (sc->sc_flags & AUE_FLAG_PII)
605109864Sjeff		aue_reset_pegasus_II(sc);
606113357Sjeff
607109864Sjeff	/* Wait a little while for the chip to get its brains in order: */
608109864Sjeff	usb2_ether_pause(&sc->sc_ue, hz / 100);
609109864Sjeff}
610112966Sjeff
611112994Sjeffstatic void
612109864Sjeffaue_attach_post(struct usb2_ether *ue)
613112966Sjeff{
614112966Sjeff	struct aue_softc *sc = usb2_ether_getsc(ue);
615109864Sjeff
616113357Sjeff	/* reset the adapter */
617112966Sjeff	aue_reset(sc);
618109864Sjeff
619112966Sjeff	/* get station address from the EEPROM */
620113357Sjeff	aue_read_eeprom(sc, ue->ue_eaddr, 0, 3);
621109864Sjeff}
622112966Sjeff
623112966Sjeff/*
624112966Sjeff * Probe for a Pegasus chip.
625112966Sjeff */
626112966Sjeffstatic int
627112966Sjeffaue_probe(device_t dev)
628112966Sjeff{
629112966Sjeff	struct usb2_attach_arg *uaa = device_get_ivars(dev);
630112966Sjeff
631112966Sjeff	if (uaa->usb_mode != USB_MODE_HOST)
632112966Sjeff		return (ENXIO);
633112966Sjeff	if (uaa->info.bConfigIndex != AUE_CONFIG_INDEX)
634112966Sjeff		return (ENXIO);
635112966Sjeff	if (uaa->info.bIfaceIndex != AUE_IFACE_IDX)
636112966Sjeff		return (ENXIO);
637112966Sjeff	/*
638112966Sjeff	 * Belkin USB Bluetooth dongles of the F8T012xx1 model series conflict
639112966Sjeff	 * with older Belkin USB2LAN adapters.  Skip if_aue if we detect one of
640112966Sjeff	 * the devices that look like Bluetooth adapters.
641112966Sjeff	 */
642112966Sjeff	if (uaa->info.idVendor == USB_VENDOR_BELKIN &&
643112966Sjeff	    uaa->info.idProduct == USB_PRODUCT_BELKIN_F8T012 &&
644109864Sjeff	    uaa->info.bcdDevice == 0x0413)
645113357Sjeff		return (ENXIO);
646112966Sjeff
647112966Sjeff	return (usb2_lookup_id_by_uaa(aue_devs, sizeof(aue_devs), uaa));
648113357Sjeff}
649113357Sjeff
650113357Sjeff/*
651112966Sjeff * Attach the interface. Allocate softc structures, do ifmedia
652113357Sjeff * setup and ethernet/BPF attach.
653112966Sjeff */
654112966Sjeffstatic int
655112966Sjeffaue_attach(device_t dev)
656112966Sjeff{
657112966Sjeff	struct usb2_attach_arg *uaa = device_get_ivars(dev);
658112966Sjeff	struct aue_softc *sc = device_get_softc(dev);
659113357Sjeff	struct usb2_ether *ue = &sc->sc_ue;
660113357Sjeff	uint8_t iface_index;
661113357Sjeff	int error;
662113357Sjeff
663113357Sjeff	sc->sc_flags = USB_GET_DRIVER_INFO(uaa);
664110645Sjeff
665112994Sjeff	if (uaa->info.bcdDevice >= 0x0201) {
666112994Sjeff		/* XXX currently undocumented */
667112994Sjeff		sc->sc_flags |= AUE_FLAG_VER_2;
668110645Sjeff	}
669116463Sjeff
670110645Sjeff	device_set_usb2_desc(dev);
671112966Sjeff	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
672109864Sjeff
673109864Sjeff	iface_index = AUE_IFACE_IDX;
674116463Sjeff	error = usb2_transfer_setup(uaa->device, &iface_index,
675116463Sjeff	    sc->sc_xfer, aue_config, AUE_N_TRANSFER,
676116463Sjeff	    sc, &sc->sc_mtx);
677121126Sjeff	if (error) {
678121126Sjeff		device_printf(dev, "allocating USB transfers failed!\n");
679121126Sjeff		goto detach;
680121126Sjeff	}
681116463Sjeff
682116463Sjeff	ue->ue_sc = sc;
683116463Sjeff	ue->ue_dev = dev;
684111857Sjeff	ue->ue_udev = uaa->device;
685111857Sjeff	ue->ue_mtx = &sc->sc_mtx;
686111857Sjeff	ue->ue_methods = &aue_ue_methods;
687116365Sjeff
688111857Sjeff	error = usb2_ether_ifattach(ue);
689111857Sjeff	if (error) {
690116365Sjeff		device_printf(dev, "could not attach interface\n");
691116365Sjeff		goto detach;
692116365Sjeff	}
693116365Sjeff	return (0);			/* success */
694116365Sjeff
695116365Sjeffdetach:
696111857Sjeff	aue_detach(dev);
697111857Sjeff	return (ENXIO);			/* failure */
698116365Sjeff}
699116365Sjeff
700116365Sjeffstatic int
701116365Sjeffaue_detach(device_t dev)
702111857Sjeff{
703111857Sjeff	struct aue_softc *sc = device_get_softc(dev);
704111857Sjeff	struct usb2_ether *ue = &sc->sc_ue;
705113357Sjeff
706113357Sjeff	usb2_transfer_unsetup(sc->sc_xfer, AUE_N_TRANSFER);
707113357Sjeff	usb2_ether_ifdetach(ue);
708113357Sjeff	mtx_destroy(&sc->sc_mtx);
709113357Sjeff
710109864Sjeff	return (0);
711109864Sjeff}
712109864Sjeff
713109864Sjeffstatic void
714109864Sjeffaue_intr_callback(struct usb2_xfer *xfer)
715109864Sjeff{
716109864Sjeff	struct aue_softc *sc = xfer->priv_sc;
717109864Sjeff	struct ifnet *ifp = usb2_ether_getifp(&sc->sc_ue);
718109864Sjeff	struct aue_intrpkt pkt;
719109864Sjeff
720109864Sjeff	switch (USB_GET_STATE(xfer)) {
721116365Sjeff	case USB_ST_TRANSFERRED:
722120272Sjeff
723120272Sjeff		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) &&
724120272Sjeff		    xfer->actlen >= sizeof(pkt)) {
725120272Sjeff
726120272Sjeff			usb2_copy_out(xfer->frbuffers, 0, &pkt, sizeof(pkt));
727120272Sjeff
728120272Sjeff			if (pkt.aue_txstat0)
729120272Sjeff				ifp->if_oerrors++;
730120272Sjeff			if (pkt.aue_txstat0 & (AUE_TXSTAT0_LATECOLL &
731120272Sjeff			    AUE_TXSTAT0_EXCESSCOLL))
732120272Sjeff				ifp->if_collisions++;
733109864Sjeff		}
734109864Sjeff		/* FALLTHROUGH */
735109864Sjeff	case USB_ST_SETUP:
736109864Sjefftr_setup:
737109864Sjeff		xfer->frlengths[0] = xfer->max_data_length;
738110267Sjeff		usb2_start_hardware(xfer);
739109864Sjeff		return;
740109864Sjeff
741109864Sjeff	default:			/* Error */
742110028Sjeff		if (xfer->error != USB_ERR_CANCELLED) {
743110028Sjeff			/* try to clear stall first */
744109864Sjeff			xfer->flags.stall_pipe = 1;
745109864Sjeff			goto tr_setup;
746109864Sjeff		}
747115998Sjeff		return;
748109864Sjeff	}
749109864Sjeff}
750109864Sjeff
751110028Sjeffstatic void
752110028Sjeffaue_bulk_read_callback(struct usb2_xfer *xfer)
753109864Sjeff{
754109864Sjeff	struct aue_softc *sc = xfer->priv_sc;
755116970Sjeff	struct usb2_ether *ue = &sc->sc_ue;
756109864Sjeff	struct ifnet *ifp = usb2_ether_getifp(ue);
757110028Sjeff	struct aue_rxpkt stat;
758113357Sjeff
759109864Sjeff	switch (USB_GET_STATE(xfer)) {
760113357Sjeff	case USB_ST_TRANSFERRED:
761109864Sjeff		DPRINTFN(11, "received %d bytes\n", xfer->actlen);
762109864Sjeff
763109864Sjeff		if (sc->sc_flags & AUE_FLAG_VER_2) {
764109864Sjeff
765109864Sjeff			if (xfer->actlen == 0) {
766109864Sjeff				ifp->if_ierrors++;
767109864Sjeff				goto tr_setup;
768109864Sjeff			}
769109864Sjeff		} else {
770109864Sjeff
771109864Sjeff			if (xfer->actlen <= (sizeof(stat) + ETHER_CRC_LEN)) {
772109864Sjeff				ifp->if_ierrors++;
773109864Sjeff				goto tr_setup;
774109864Sjeff			}
775109864Sjeff			usb2_copy_out(xfer->frbuffers,
776109864Sjeff			    xfer->actlen - sizeof(stat), &stat, sizeof(stat));
777109864Sjeff
778109864Sjeff			/*
779109864Sjeff			 * turn off all the non-error bits in the rx status
780109864Sjeff			 * word:
781119488Sdavidxu			 */
782119488Sdavidxu			stat.aue_rxstat &= AUE_RXSTAT_MASK;
783119488Sdavidxu			if (stat.aue_rxstat) {
784109864Sjeff				ifp->if_ierrors++;
785109864Sjeff				goto tr_setup;
786109864Sjeff			}
787109864Sjeff			/* No errors; receive the packet. */
788121128Sjeff			xfer->actlen -= (sizeof(stat) + ETHER_CRC_LEN);
789109864Sjeff		}
790121128Sjeff		usb2_ether_rxbuf(ue, xfer->frbuffers, 0, xfer->actlen);
791121128Sjeff
792109864Sjeff		/* FALLTHROUGH */
793109864Sjeff	case USB_ST_SETUP:
794109864Sjefftr_setup:
795109864Sjeff		xfer->frlengths[0] = xfer->max_data_length;
796109864Sjeff		usb2_start_hardware(xfer);
797109864Sjeff		usb2_ether_rxflush(ue);
798109864Sjeff		return;
799113339Sjulian
800113339Sjulian	default:			/* Error */
801111032Sjulian		DPRINTF("bulk read error, %s\n",
802109864Sjeff		    usb2_errstr(xfer->error));
803109864Sjeff
804119488Sdavidxu		if (xfer->error != USB_ERR_CANCELLED) {
805119488Sdavidxu			/* try to clear stall first */
806119488Sdavidxu			xfer->flags.stall_pipe = 1;
807119488Sdavidxu			goto tr_setup;
808119488Sdavidxu		}
809119488Sdavidxu		return;
810119488Sdavidxu	}
811119488Sdavidxu}
812119488Sdavidxu
813119488Sdavidxustatic void
814119488Sdavidxuaue_bulk_write_callback(struct usb2_xfer *xfer)
815119488Sdavidxu{
816119488Sdavidxu	struct aue_softc *sc = xfer->priv_sc;
817119488Sdavidxu	struct ifnet *ifp = usb2_ether_getifp(&sc->sc_ue);
818121146Sjeff	struct mbuf *m;
819121146Sjeff	uint8_t buf[2];
820121146Sjeff
821121146Sjeff	switch (USB_GET_STATE(xfer)) {
822121146Sjeff	case USB_ST_TRANSFERRED:
823121146Sjeff		DPRINTFN(11, "transfer of %d bytes complete\n", xfer->actlen);
824121146Sjeff		ifp->if_opackets++;
825121146Sjeff
826121146Sjeff		/* FALLTHROUGH */
827121146Sjeff	case USB_ST_SETUP:
828121128Sjefftr_setup:
829121128Sjeff		if ((sc->sc_flags & AUE_FLAG_LINK) == 0) {
830121128Sjeff			/*
831121128Sjeff			 * don't send anything if there is no link !
832121128Sjeff			 */
833121128Sjeff			return;
834109864Sjeff		}
835113339Sjulian		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
836109864Sjeff
837109864Sjeff		if (m == NULL)
838109864Sjeff			return;
839109864Sjeff		if (m->m_pkthdr.len > MCLBYTES)
840109864Sjeff			m->m_pkthdr.len = MCLBYTES;
841113357Sjeff		if (sc->sc_flags & AUE_FLAG_VER_2) {
842109864Sjeff
843113357Sjeff			xfer->frlengths[0] = m->m_pkthdr.len;
844109864Sjeff
845113873Sjhb			usb2_m_copy_in(xfer->frbuffers, 0,
846113873Sjhb			    m, 0, m->m_pkthdr.len);
847113357Sjeff
848113357Sjeff		} else {
849113357Sjeff
850113357Sjeff			xfer->frlengths[0] = (m->m_pkthdr.len + 2);
851113357Sjeff
852116500Sjeff			/*
853113357Sjeff		         * The ADMtek documentation says that the
854113357Sjeff		         * packet length is supposed to be specified
855113357Sjeff		         * in the first two bytes of the transfer,
856113357Sjeff		         * however it actually seems to ignore this
857113357Sjeff		         * info and base the frame size on the bulk
858109864Sjeff		         * transfer length.
859109864Sjeff		         */
860113357Sjeff			buf[0] = (uint8_t)(m->m_pkthdr.len);
861111032Sjulian			buf[1] = (uint8_t)(m->m_pkthdr.len >> 8);
862109864Sjeff
863109864Sjeff			usb2_copy_in(xfer->frbuffers, 0, buf, 2);
864109864Sjeff
865109864Sjeff			usb2_m_copy_in(xfer->frbuffers, 2,
866109864Sjeff			    m, 0, m->m_pkthdr.len);
867109864Sjeff		}
868109864Sjeff
869109864Sjeff		/*
870109864Sjeff		 * if there's a BPF listener, bounce a copy
871109864Sjeff		 * of this frame to him:
872113357Sjeff		 */
873113357Sjeff		BPF_MTAP(ifp, m);
874109864Sjeff
875109864Sjeff		m_freem(m);
876109864Sjeff
877109864Sjeff		usb2_start_hardware(xfer);
878109864Sjeff		return;
879109864Sjeff
880109864Sjeff	default:			/* Error */
881109864Sjeff		DPRINTFN(11, "transfer error, %s\n",
882109864Sjeff		    usb2_errstr(xfer->error));
883109864Sjeff
884109864Sjeff		ifp->if_oerrors++;
885111788Sjeff
886111788Sjeff		if (xfer->error != USB_ERR_CANCELLED) {
887113357Sjeff			/* try to clear stall first */
888109864Sjeff			xfer->flags.stall_pipe = 1;
889111788Sjeff			goto tr_setup;
890113357Sjeff		}
891113357Sjeff		return;
892116463Sjeff	}
893111788Sjeff}
894116463Sjeff
895116463Sjeffstatic void
896113357Sjeffaue_tick(struct usb2_ether *ue)
897113357Sjeff{
898111788Sjeff	struct aue_softc *sc = usb2_ether_getsc(ue);
899109864Sjeff	struct mii_data *mii = GET_MII(sc);
900109864Sjeff
901109864Sjeff	AUE_LOCK_ASSERT(sc, MA_OWNED);
902111032Sjulian
903109864Sjeff	mii_tick(mii);
904109864Sjeff	if ((sc->sc_flags & AUE_FLAG_LINK) == 0
905109864Sjeff	    && mii->mii_media_status & IFM_ACTIVE &&
906109864Sjeff	    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
907109864Sjeff		sc->sc_flags |= AUE_FLAG_LINK;
908109864Sjeff		aue_start(ue);
909109864Sjeff	}
910113357Sjeff}
911109864Sjeff
912109864Sjeffstatic void
913109864Sjeffaue_start(struct usb2_ether *ue)
914109864Sjeff{
915113357Sjeff	struct aue_softc *sc = usb2_ether_getsc(ue);
916113357Sjeff
917113357Sjeff	/*
918113357Sjeff	 * start the USB transfers, if not already started:
919113357Sjeff	 */
920113357Sjeff	usb2_transfer_start(sc->sc_xfer[AUE_INTR_DT_RD]);
921113357Sjeff	usb2_transfer_start(sc->sc_xfer[AUE_BULK_DT_RD]);
922113357Sjeff	usb2_transfer_start(sc->sc_xfer[AUE_BULK_DT_WR]);
923113923Sjhb}
924116365Sjeff
925113357Sjeffstatic void
926113357Sjeffaue_init(struct usb2_ether *ue)
927113357Sjeff{
928121051Sjeff	struct aue_softc *sc = usb2_ether_getsc(ue);
929121051Sjeff	struct ifnet *ifp = usb2_ether_getifp(ue);
930121051Sjeff	int i;
931121051Sjeff
932113357Sjeff	AUE_LOCK_ASSERT(sc, MA_OWNED);
933113357Sjeff
934113357Sjeff	/*
935113357Sjeff	 * Cancel pending I/O
936113357Sjeff	 */
937113923Sjhb	aue_reset(sc);
938113923Sjhb
939109864Sjeff	/* Set MAC address */
940116365Sjeff	for (i = 0; i != ETHER_ADDR_LEN; i++)
941116955Sjeff		aue_csr_write_1(sc, AUE_PAR0 + i, IF_LLADDR(ifp)[i]);
942116955Sjeff
943116463Sjeff	/* update promiscuous setting */
944116463Sjeff	aue_setpromisc(ue);
945113357Sjeff
946109864Sjeff	/* Load the multicast filter. */
947113357Sjeff	aue_setmulti(ue);
948113357Sjeff
949109864Sjeff	/* Enable RX and TX */
950113357Sjeff	aue_csr_write_1(sc, AUE_CTL0, AUE_CTL0_RXSTAT_APPEND | AUE_CTL0_RX_ENB);
951113357Sjeff	AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_TX_ENB);
952113357Sjeff	AUE_SETBIT(sc, AUE_CTL2, AUE_CTL2_EP3_CLR);
953113357Sjeff
954113357Sjeff	usb2_transfer_set_stall(sc->sc_xfer[AUE_BULK_DT_WR]);
955113357Sjeff
956113357Sjeff	ifp->if_drv_flags |= IFF_DRV_RUNNING;
957113357Sjeff	aue_start(ue);
958113357Sjeff}
959113357Sjeff
960113357Sjeffstatic void
961113923Sjhbaue_setpromisc(struct usb2_ether *ue)
962113357Sjeff{
963113357Sjeff	struct aue_softc *sc = usb2_ether_getsc(ue);
964113357Sjeff	struct ifnet *ifp = usb2_ether_getifp(ue);
965113357Sjeff
966113357Sjeff	AUE_LOCK_ASSERT(sc, MA_OWNED);
967113357Sjeff
968113357Sjeff	/* if we want promiscuous mode, set the allframes bit: */
969113357Sjeff	if (ifp->if_flags & IFF_PROMISC)
970113357Sjeff		AUE_SETBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC);
971113386Sjeff	else
972113386Sjeff		AUE_CLRBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC);
973113357Sjeff}
974113357Sjeff
975113357Sjeff/*
976113357Sjeff * Set media options.
977113357Sjeff */
978109970Sjeffstatic int
979109970Sjeffaue_ifmedia_upd(struct ifnet *ifp)
980113357Sjeff{
981109864Sjeff	struct aue_softc *sc = ifp->if_softc;
982109864Sjeff	struct mii_data *mii = GET_MII(sc);
983109864Sjeff
984109864Sjeff	AUE_LOCK_ASSERT(sc, MA_OWNED);
985109864Sjeff
986109864Sjeff        sc->sc_flags &= ~AUE_FLAG_LINK;
987113357Sjeff	if (mii->mii_instance) {
988109864Sjeff		struct mii_softc *miisc;
989109864Sjeff
990109864Sjeff		LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
991113372Sjeff			mii_phy_reset(miisc);
992116365Sjeff	}
993109864Sjeff	mii_mediachg(mii);
994109864Sjeff	return (0);
995109864Sjeff}
996113372Sjeff
997113372Sjeff/*
998113372Sjeff * Report current media status.
999113372Sjeff */
1000113372Sjeffstatic void
1001113372Sjeffaue_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
1002113372Sjeff{
1003113372Sjeff	struct aue_softc *sc = ifp->if_softc;
1004116463Sjeff	struct mii_data *mii = GET_MII(sc);
1005116365Sjeff
1006116463Sjeff	AUE_LOCK(sc);
1007113372Sjeff	mii_pollstat(mii);
1008113372Sjeff	AUE_UNLOCK(sc);
1009113372Sjeff	ifmr->ifm_active = mii->mii_media_active;
1010113372Sjeff	ifmr->ifm_status = mii->mii_media_status;
1011113372Sjeff}
1012113372Sjeff
1013113372Sjeff/*
1014113372Sjeff * Stop the adapter and free any mbufs allocated to the
1015121127Sjeff * RX and TX lists.
1016109864Sjeff */
1017113357Sjeffstatic void
1018113357Sjeffaue_stop(struct usb2_ether *ue)
1019121127Sjeff{
1020113357Sjeff	struct aue_softc *sc = usb2_ether_getsc(ue);
1021109864Sjeff	struct ifnet *ifp = usb2_ether_getifp(ue);
1022110267Sjeff
1023109864Sjeff	AUE_LOCK_ASSERT(sc, MA_OWNED);
1024113357Sjeff
1025113357Sjeff	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1026113357Sjeff	sc->sc_flags &= ~AUE_FLAG_LINK;
1027113357Sjeff
1028113357Sjeff	/*
1029113357Sjeff	 * stop all the transfers, if not already stopped:
1030113357Sjeff	 */
1031113357Sjeff	usb2_transfer_stop(sc->sc_xfer[AUE_BULK_DT_WR]);
1032113357Sjeff	usb2_transfer_stop(sc->sc_xfer[AUE_BULK_DT_RD]);
1033113357Sjeff	usb2_transfer_stop(sc->sc_xfer[AUE_INTR_DT_RD]);
1034113357Sjeff
1035113357Sjeff	aue_csr_write_1(sc, AUE_CTL0, 0);
1036113357Sjeff	aue_csr_write_1(sc, AUE_CTL1, 0);
1037113357Sjeff	aue_reset(sc);
1038113357Sjeff}
1039109864Sjeff