if_udav.c revision 194228
1184610Salfred/*	$NetBSD: if_udav.c,v 1.2 2003/09/04 15:17:38 tsutsui Exp $	*/
2184610Salfred/*	$nabe: if_udav.c,v 1.3 2003/08/21 16:57:19 nabe Exp $	*/
3184610Salfred/*	$FreeBSD: head/sys/dev/usb/net/if_udav.c 194228 2009-06-15 01:02:43Z thompsa $	*/
4184610Salfred/*-
5184610Salfred * Copyright (c) 2003
6184610Salfred *     Shingo WATANABE <nabe@nabechan.org>.  All rights reserved.
7184610Salfred *
8184610Salfred * Redistribution and use in source and binary forms, with or without
9184610Salfred * modification, are permitted provided that the following conditions
10184610Salfred * are met:
11184610Salfred * 1. Redistributions of source code must retain the above copyright
12184610Salfred *    notice, this list of conditions and the following disclaimer.
13184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
14184610Salfred *    notice, this list of conditions and the following disclaimer in the
15184610Salfred *    documentation and/or other materials provided with the distribution.
16184610Salfred * 3. Neither the name of the author nor the names of any co-contributors
17184610Salfred *    may be used to endorse or promote products derived from this software
18184610Salfred *    without specific prior written permission.
19184610Salfred *
20184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23184610Salfred * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30184610Salfred * SUCH DAMAGE.
31184610Salfred *
32184610Salfred */
33184610Salfred
34184610Salfred/*
35184610Salfred * DM9601(DAVICOM USB to Ethernet MAC Controller with Integrated 10/100 PHY)
36184610Salfred * The spec can be found at the following url.
37184610Salfred *   http://www.davicom.com.tw/big5/download/Data%20Sheet/DM9601-DS-P01-930914.pdf
38184610Salfred */
39184610Salfred
40184610Salfred/*
41184610Salfred * TODO:
42184610Salfred *	Interrupt Endpoint support
43184610Salfred *	External PHYs
44184610Salfred */
45184610Salfred
46184610Salfred#include <sys/cdefs.h>
47184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb/net/if_udav.c 194228 2009-06-15 01:02:43Z thompsa $");
48184610Salfred
49188746Sthompsa#include "usbdevs.h"
50188942Sthompsa#include <dev/usb/usb.h>
51188942Sthompsa#include <dev/usb/usb_mfunc.h>
52188942Sthompsa#include <dev/usb/usb_error.h>
53184610Salfred
54184610Salfred#define	USB_DEBUG_VAR udav_debug
55184610Salfred
56188942Sthompsa#include <dev/usb/usb_core.h>
57188942Sthompsa#include <dev/usb/usb_lookup.h>
58188942Sthompsa#include <dev/usb/usb_process.h>
59188942Sthompsa#include <dev/usb/usb_debug.h>
60188942Sthompsa#include <dev/usb/usb_request.h>
61188942Sthompsa#include <dev/usb/usb_busdma.h>
62188942Sthompsa#include <dev/usb/usb_util.h>
63184610Salfred
64188942Sthompsa#include <dev/usb/net/usb_ethernet.h>
65188942Sthompsa#include <dev/usb/net/if_udavreg.h>
66184610Salfred
67184610Salfred/* prototypes */
68184610Salfred
69184610Salfredstatic device_probe_t udav_probe;
70184610Salfredstatic device_attach_t udav_attach;
71184610Salfredstatic device_detach_t udav_detach;
72184610Salfred
73193045Sthompsastatic usb_callback_t udav_bulk_write_callback;
74193045Sthompsastatic usb_callback_t udav_bulk_read_callback;
75193045Sthompsastatic usb_callback_t udav_intr_callback;
76184610Salfred
77193045Sthompsastatic uether_fn_t udav_attach_post;
78193045Sthompsastatic uether_fn_t udav_init;
79193045Sthompsastatic uether_fn_t udav_stop;
80193045Sthompsastatic uether_fn_t udav_start;
81193045Sthompsastatic uether_fn_t udav_tick;
82193045Sthompsastatic uether_fn_t udav_setmulti;
83193045Sthompsastatic uether_fn_t udav_setpromisc;
84184610Salfred
85188412Sthompsastatic int	udav_csr_read(struct udav_softc *, uint16_t, void *, int);
86188412Sthompsastatic int	udav_csr_write(struct udav_softc *, uint16_t, void *, int);
87188412Sthompsastatic uint8_t	udav_csr_read1(struct udav_softc *, uint16_t);
88188412Sthompsastatic int	udav_csr_write1(struct udav_softc *, uint16_t, uint8_t);
89188412Sthompsastatic void	udav_reset(struct udav_softc *);
90188412Sthompsastatic int	udav_ifmedia_upd(struct ifnet *);
91188412Sthompsastatic void	udav_ifmedia_status(struct ifnet *, struct ifmediareq *);
92184610Salfred
93188412Sthompsastatic miibus_readreg_t udav_miibus_readreg;
94188412Sthompsastatic miibus_writereg_t udav_miibus_writereg;
95188412Sthompsastatic miibus_statchg_t udav_miibus_statchg;
96184610Salfred
97192984Sthompsastatic const struct usb_config udav_config[UDAV_N_TRANSFER] = {
98184610Salfred
99187259Sthompsa	[UDAV_BULK_DT_WR] = {
100184610Salfred		.type = UE_BULK,
101184610Salfred		.endpoint = UE_ADDR_ANY,
102184610Salfred		.direction = UE_DIR_OUT,
103190734Sthompsa		.bufsize = (MCLBYTES + 2),
104190734Sthompsa		.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
105190734Sthompsa		.callback = udav_bulk_write_callback,
106190734Sthompsa		.timeout = 10000,	/* 10 seconds */
107184610Salfred	},
108184610Salfred
109187259Sthompsa	[UDAV_BULK_DT_RD] = {
110184610Salfred		.type = UE_BULK,
111184610Salfred		.endpoint = UE_ADDR_ANY,
112184610Salfred		.direction = UE_DIR_IN,
113190734Sthompsa		.bufsize = (MCLBYTES + 3),
114190734Sthompsa		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
115190734Sthompsa		.callback = udav_bulk_read_callback,
116190734Sthompsa		.timeout = 0,	/* no timeout */
117184610Salfred	},
118184610Salfred
119187259Sthompsa	[UDAV_INTR_DT_RD] = {
120184610Salfred		.type = UE_INTERRUPT,
121184610Salfred		.endpoint = UE_ADDR_ANY,
122184610Salfred		.direction = UE_DIR_IN,
123190734Sthompsa		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
124190734Sthompsa		.bufsize = 0,	/* use wMaxPacketSize */
125190734Sthompsa		.callback = udav_intr_callback,
126184610Salfred	},
127184610Salfred};
128184610Salfred
129184610Salfredstatic device_method_t udav_methods[] = {
130184610Salfred	/* Device interface */
131184610Salfred	DEVMETHOD(device_probe, udav_probe),
132184610Salfred	DEVMETHOD(device_attach, udav_attach),
133184610Salfred	DEVMETHOD(device_detach, udav_detach),
134184610Salfred
135184610Salfred	/* bus interface */
136184610Salfred	DEVMETHOD(bus_print_child, bus_generic_print_child),
137184610Salfred	DEVMETHOD(bus_driver_added, bus_generic_driver_added),
138184610Salfred
139184610Salfred	/* MII interface */
140188412Sthompsa	DEVMETHOD(miibus_readreg, udav_miibus_readreg),
141188412Sthompsa	DEVMETHOD(miibus_writereg, udav_miibus_writereg),
142188412Sthompsa	DEVMETHOD(miibus_statchg, udav_miibus_statchg),
143184610Salfred
144184610Salfred	{0, 0}
145184610Salfred};
146184610Salfred
147184610Salfredstatic driver_t udav_driver = {
148184610Salfred	.name = "udav",
149184610Salfred	.methods = udav_methods,
150184610Salfred	.size = sizeof(struct udav_softc),
151184610Salfred};
152184610Salfred
153184610Salfredstatic devclass_t udav_devclass;
154184610Salfred
155189275SthompsaDRIVER_MODULE(udav, uhub, udav_driver, udav_devclass, NULL, 0);
156184610SalfredDRIVER_MODULE(miibus, udav, miibus_driver, miibus_devclass, 0, 0);
157188942SthompsaMODULE_DEPEND(udav, uether, 1, 1, 1);
158188942SthompsaMODULE_DEPEND(udav, usb, 1, 1, 1);
159184610SalfredMODULE_DEPEND(udav, ether, 1, 1, 1);
160184610SalfredMODULE_DEPEND(udav, miibus, 1, 1, 1);
161184610Salfred
162192984Sthompsastatic const struct usb_ether_methods udav_ue_methods = {
163188412Sthompsa	.ue_attach_post = udav_attach_post,
164188412Sthompsa	.ue_start = udav_start,
165188412Sthompsa	.ue_init = udav_init,
166188412Sthompsa	.ue_stop = udav_stop,
167188412Sthompsa	.ue_tick = udav_tick,
168188412Sthompsa	.ue_setmulti = udav_setmulti,
169188412Sthompsa	.ue_setpromisc = udav_setpromisc,
170188412Sthompsa	.ue_mii_upd = udav_ifmedia_upd,
171188412Sthompsa	.ue_mii_sts = udav_ifmedia_status,
172188412Sthompsa};
173188412Sthompsa
174184610Salfred#if USB_DEBUG
175184610Salfredstatic int udav_debug = 0;
176184610Salfred
177192502SthompsaSYSCTL_NODE(_hw_usb, OID_AUTO, udav, CTLFLAG_RW, 0, "USB udav");
178192502SthompsaSYSCTL_INT(_hw_usb_udav, OID_AUTO, debug, CTLFLAG_RW, &udav_debug, 0,
179184610Salfred    "Debug level");
180184610Salfred#endif
181184610Salfred
182188412Sthompsa#define	UDAV_SETBIT(sc, reg, x)	\
183188412Sthompsa	udav_csr_write1(sc, reg, udav_csr_read1(sc, reg) | (x))
184184610Salfred
185188412Sthompsa#define	UDAV_CLRBIT(sc, reg, x)	\
186188412Sthompsa	udav_csr_write1(sc, reg, udav_csr_read1(sc, reg) & ~(x))
187184610Salfred
188192984Sthompsastatic const struct usb_device_id udav_devs[] = {
189184610Salfred	/* ShanTou DM9601 USB NIC */
190184610Salfred	{USB_VPI(USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_DM9601, 0)},
191184610Salfred	/* ShanTou ST268 USB NIC */
192184610Salfred	{USB_VPI(USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_ST268, 0)},
193184610Salfred	/* Corega USB-TXC */
194184610Salfred	{USB_VPI(USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TXC, 0)},
195184610Salfred};
196184610Salfred
197188412Sthompsastatic void
198192984Sthompsaudav_attach_post(struct usb_ether *ue)
199188412Sthompsa{
200194228Sthompsa	struct udav_softc *sc = uether_getsc(ue);
201188412Sthompsa
202188412Sthompsa	/* reset the adapter */
203188412Sthompsa	udav_reset(sc);
204188412Sthompsa
205188412Sthompsa	/* Get Ethernet Address */
206188412Sthompsa	udav_csr_read(sc, UDAV_PAR, ue->ue_eaddr, ETHER_ADDR_LEN);
207188412Sthompsa}
208188412Sthompsa
209184610Salfredstatic int
210184610Salfredudav_probe(device_t dev)
211184610Salfred{
212192984Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(dev);
213184610Salfred
214192499Sthompsa	if (uaa->usb_mode != USB_MODE_HOST)
215184610Salfred		return (ENXIO);
216188412Sthompsa	if (uaa->info.bConfigIndex != UDAV_CONFIG_INDEX)
217184610Salfred		return (ENXIO);
218188412Sthompsa	if (uaa->info.bIfaceIndex != UDAV_IFACE_INDEX)
219184610Salfred		return (ENXIO);
220188412Sthompsa
221194228Sthompsa	return (usbd_lookup_id_by_uaa(udav_devs, sizeof(udav_devs), uaa));
222184610Salfred}
223184610Salfred
224184610Salfredstatic int
225184610Salfredudav_attach(device_t dev)
226184610Salfred{
227192984Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(dev);
228184610Salfred	struct udav_softc *sc = device_get_softc(dev);
229192984Sthompsa	struct usb_ether *ue = &sc->sc_ue;
230184610Salfred	uint8_t iface_index;
231188412Sthompsa	int error;
232184610Salfred
233184610Salfred	sc->sc_flags = USB_GET_DRIVER_INFO(uaa);
234184610Salfred
235194228Sthompsa	device_set_usb_desc(dev);
236184610Salfred
237188412Sthompsa	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
238184610Salfred
239184610Salfred	iface_index = UDAV_IFACE_INDEX;
240194228Sthompsa	error = usbd_transfer_setup(uaa->device, &iface_index,
241187259Sthompsa	    sc->sc_xfer, udav_config, UDAV_N_TRANSFER, sc, &sc->sc_mtx);
242184610Salfred	if (error) {
243188412Sthompsa		device_printf(dev, "allocating USB transfers failed!\n");
244184610Salfred		goto detach;
245184610Salfred	}
246188412Sthompsa
247188412Sthompsa	ue->ue_sc = sc;
248188412Sthompsa	ue->ue_dev = dev;
249188412Sthompsa	ue->ue_udev = uaa->device;
250188412Sthompsa	ue->ue_mtx = &sc->sc_mtx;
251188412Sthompsa	ue->ue_methods = &udav_ue_methods;
252188412Sthompsa
253194228Sthompsa	error = uether_ifattach(ue);
254184610Salfred	if (error) {
255188412Sthompsa		device_printf(dev, "could not attach interface\n");
256184610Salfred		goto detach;
257184610Salfred	}
258184610Salfred
259184610Salfred	return (0);			/* success */
260184610Salfred
261184610Salfreddetach:
262184610Salfred	udav_detach(dev);
263184610Salfred	return (ENXIO);			/* failure */
264184610Salfred}
265184610Salfred
266184610Salfredstatic int
267184610Salfredudav_detach(device_t dev)
268184610Salfred{
269184610Salfred	struct udav_softc *sc = device_get_softc(dev);
270192984Sthompsa	struct usb_ether *ue = &sc->sc_ue;
271184610Salfred
272194228Sthompsa	usbd_transfer_unsetup(sc->sc_xfer, UDAV_N_TRANSFER);
273194228Sthompsa	uether_ifdetach(ue);
274184610Salfred	mtx_destroy(&sc->sc_mtx);
275184610Salfred
276184610Salfred	return (0);
277184610Salfred}
278184610Salfred
279184610Salfred#if 0
280188412Sthompsastatic int
281188412Sthompsaudav_mem_read(struct udav_softc *sc, uint16_t offset, void *buf,
282188412Sthompsa    int len)
283184610Salfred{
284192984Sthompsa	struct usb_device_request req;
285184610Salfred
286184610Salfred	len &= 0xff;
287184610Salfred
288184610Salfred	req.bmRequestType = UT_READ_VENDOR_DEVICE;
289184610Salfred	req.bRequest = UDAV_REQ_MEM_READ;
290184610Salfred	USETW(req.wValue, 0x0000);
291184610Salfred	USETW(req.wIndex, offset);
292184610Salfred	USETW(req.wLength, len);
293184610Salfred
294194228Sthompsa	return (uether_do_request(&sc->sc_ue, &req, buf, 1000));
295184610Salfred}
296184610Salfred
297188412Sthompsastatic int
298188412Sthompsaudav_mem_write(struct udav_softc *sc, uint16_t offset, void *buf,
299188412Sthompsa    int len)
300184610Salfred{
301192984Sthompsa	struct usb_device_request req;
302184610Salfred
303184610Salfred	len &= 0xff;
304184610Salfred
305184610Salfred	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
306184610Salfred	req.bRequest = UDAV_REQ_MEM_WRITE;
307184610Salfred	USETW(req.wValue, 0x0000);
308184610Salfred	USETW(req.wIndex, offset);
309184610Salfred	USETW(req.wLength, len);
310184610Salfred
311194228Sthompsa	return (uether_do_request(&sc->sc_ue, &req, buf, 1000));
312184610Salfred}
313184610Salfred
314188412Sthompsastatic int
315188412Sthompsaudav_mem_write1(struct udav_softc *sc, uint16_t offset,
316184610Salfred    uint8_t ch)
317184610Salfred{
318192984Sthompsa	struct usb_device_request req;
319184610Salfred
320184610Salfred	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
321184610Salfred	req.bRequest = UDAV_REQ_MEM_WRITE1;
322184610Salfred	USETW(req.wValue, ch);
323184610Salfred	USETW(req.wIndex, offset);
324184610Salfred	USETW(req.wLength, 0x0000);
325184610Salfred
326194228Sthompsa	return (uether_do_request(&sc->sc_ue, &req, NULL, 1000));
327184610Salfred}
328184610Salfred#endif
329184610Salfred
330188412Sthompsastatic int
331188412Sthompsaudav_csr_read(struct udav_softc *sc, uint16_t offset, void *buf, int len)
332184610Salfred{
333192984Sthompsa	struct usb_device_request req;
334184610Salfred
335184610Salfred	len &= 0xff;
336184610Salfred
337184610Salfred	req.bmRequestType = UT_READ_VENDOR_DEVICE;
338184610Salfred	req.bRequest = UDAV_REQ_REG_READ;
339184610Salfred	USETW(req.wValue, 0x0000);
340184610Salfred	USETW(req.wIndex, offset);
341184610Salfred	USETW(req.wLength, len);
342184610Salfred
343194228Sthompsa	return (uether_do_request(&sc->sc_ue, &req, buf, 1000));
344184610Salfred}
345184610Salfred
346188412Sthompsastatic int
347188412Sthompsaudav_csr_write(struct udav_softc *sc, uint16_t offset, void *buf, int len)
348184610Salfred{
349192984Sthompsa	struct usb_device_request req;
350184610Salfred
351184610Salfred	offset &= 0xff;
352184610Salfred	len &= 0xff;
353184610Salfred
354184610Salfred	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
355184610Salfred	req.bRequest = UDAV_REQ_REG_WRITE;
356184610Salfred	USETW(req.wValue, 0x0000);
357184610Salfred	USETW(req.wIndex, offset);
358184610Salfred	USETW(req.wLength, len);
359184610Salfred
360194228Sthompsa	return (uether_do_request(&sc->sc_ue, &req, buf, 1000));
361184610Salfred}
362184610Salfred
363184610Salfredstatic uint8_t
364188412Sthompsaudav_csr_read1(struct udav_softc *sc, uint16_t offset)
365184610Salfred{
366184610Salfred	uint8_t val;
367184610Salfred
368188412Sthompsa	udav_csr_read(sc, offset, &val, 1);
369184610Salfred	return (val);
370184610Salfred}
371184610Salfred
372188412Sthompsastatic int
373188412Sthompsaudav_csr_write1(struct udav_softc *sc, uint16_t offset,
374184610Salfred    uint8_t ch)
375184610Salfred{
376192984Sthompsa	struct usb_device_request req;
377184610Salfred
378184610Salfred	offset &= 0xff;
379184610Salfred
380184610Salfred	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
381184610Salfred	req.bRequest = UDAV_REQ_REG_WRITE1;
382184610Salfred	USETW(req.wValue, ch);
383184610Salfred	USETW(req.wIndex, offset);
384184610Salfred	USETW(req.wLength, 0x0000);
385184610Salfred
386194228Sthompsa	return (uether_do_request(&sc->sc_ue, &req, NULL, 1000));
387184610Salfred}
388184610Salfred
389184610Salfredstatic void
390192984Sthompsaudav_init(struct usb_ether *ue)
391184610Salfred{
392188412Sthompsa	struct udav_softc *sc = ue->ue_sc;
393194228Sthompsa	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
394184610Salfred
395188412Sthompsa	UDAV_LOCK_ASSERT(sc, MA_OWNED);
396184610Salfred
397184610Salfred	/*
398184610Salfred	 * Cancel pending I/O
399184610Salfred	 */
400188412Sthompsa	udav_stop(ue);
401184610Salfred
402184610Salfred	/* set MAC address */
403188412Sthompsa	udav_csr_write(sc, UDAV_PAR, IF_LLADDR(ifp), ETHER_ADDR_LEN);
404184610Salfred
405184610Salfred	/* initialize network control register */
406184610Salfred
407184610Salfred	/* disable loopback  */
408188412Sthompsa	UDAV_CLRBIT(sc, UDAV_NCR, UDAV_NCR_LBK0 | UDAV_NCR_LBK1);
409184610Salfred
410184610Salfred	/* Initialize RX control register */
411188412Sthompsa	UDAV_SETBIT(sc, UDAV_RCR, UDAV_RCR_DIS_LONG | UDAV_RCR_DIS_CRC);
412184610Salfred
413184610Salfred	/* load multicast filter and update promiscious mode bit */
414188412Sthompsa	udav_setpromisc(ue);
415184610Salfred
416184610Salfred	/* enable RX */
417188412Sthompsa	UDAV_SETBIT(sc, UDAV_RCR, UDAV_RCR_RXEN);
418184610Salfred
419184610Salfred	/* clear POWER_DOWN state of internal PHY */
420188412Sthompsa	UDAV_SETBIT(sc, UDAV_GPCR, UDAV_GPCR_GEP_CNTL0);
421188412Sthompsa	UDAV_CLRBIT(sc, UDAV_GPR, UDAV_GPR_GEPIO0);
422184610Salfred
423194228Sthompsa	usbd_transfer_set_stall(sc->sc_xfer[UDAV_BULK_DT_WR]);
424184610Salfred
425188412Sthompsa	ifp->if_drv_flags |= IFF_DRV_RUNNING;
426188412Sthompsa	udav_start(ue);
427184610Salfred}
428184610Salfred
429184610Salfredstatic void
430188412Sthompsaudav_reset(struct udav_softc *sc)
431184610Salfred{
432188412Sthompsa	int i;
433184610Salfred
434184610Salfred	/* Select PHY */
435184610Salfred#if 1
436184610Salfred	/*
437184610Salfred	 * XXX: force select internal phy.
438184610Salfred	 *	external phy routines are not tested.
439184610Salfred	 */
440188412Sthompsa	UDAV_CLRBIT(sc, UDAV_NCR, UDAV_NCR_EXT_PHY);
441184610Salfred#else
442188412Sthompsa	if (sc->sc_flags & UDAV_EXT_PHY)
443188412Sthompsa		UDAV_SETBIT(sc, UDAV_NCR, UDAV_NCR_EXT_PHY);
444188412Sthompsa	else
445188412Sthompsa		UDAV_CLRBIT(sc, UDAV_NCR, UDAV_NCR_EXT_PHY);
446184610Salfred#endif
447184610Salfred
448188412Sthompsa	UDAV_SETBIT(sc, UDAV_NCR, UDAV_NCR_RST);
449184610Salfred
450188412Sthompsa	for (i = 0; i < UDAV_TX_TIMEOUT; i++) {
451188412Sthompsa		if (!(udav_csr_read1(sc, UDAV_NCR) & UDAV_NCR_RST))
452184610Salfred			break;
453194228Sthompsa		if (uether_pause(&sc->sc_ue, hz / 100))
454188412Sthompsa			break;
455184610Salfred	}
456184610Salfred
457194228Sthompsa	uether_pause(&sc->sc_ue, hz / 100);
458184610Salfred}
459184610Salfred
460184610Salfred#define	UDAV_BITS	6
461184610Salfredstatic void
462192984Sthompsaudav_setmulti(struct usb_ether *ue)
463184610Salfred{
464188412Sthompsa	struct udav_softc *sc = ue->ue_sc;
465194228Sthompsa	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
466188412Sthompsa	struct ifmultiaddr *ifma;
467188412Sthompsa	uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
468188412Sthompsa	int h = 0;
469184610Salfred
470188412Sthompsa	UDAV_LOCK_ASSERT(sc, MA_OWNED);
471184610Salfred
472188412Sthompsa	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
473188412Sthompsa		UDAV_SETBIT(sc, UDAV_RCR, UDAV_RCR_ALL|UDAV_RCR_PRMSC);
474188412Sthompsa		return;
475188412Sthompsa	}
476188412Sthompsa
477188412Sthompsa	/* first, zot all the existing hash bits */
478188412Sthompsa	memset(hashtbl, 0x00, sizeof(hashtbl));
479188412Sthompsa	hashtbl[7] |= 0x80;	/* broadcast address */
480188412Sthompsa	udav_csr_write(sc, UDAV_MAR, hashtbl, sizeof(hashtbl));
481188412Sthompsa
482188412Sthompsa	/* now program new ones */
483188412Sthompsa	IF_ADDR_LOCK(ifp);
484188412Sthompsa	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
485188412Sthompsa	{
486188412Sthompsa		if (ifma->ifma_addr->sa_family != AF_LINK)
487188412Sthompsa			continue;
488188412Sthompsa		h = ether_crc32_be(LLADDR((struct sockaddr_dl *)
489188412Sthompsa		    ifma->ifma_addr), ETHER_ADDR_LEN) >> 26;
490188412Sthompsa		hashtbl[h / 8] |= 1 << (h % 8);
491188412Sthompsa	}
492188412Sthompsa	IF_ADDR_UNLOCK(ifp);
493188412Sthompsa
494188412Sthompsa	/* disable all multicast */
495188412Sthompsa	UDAV_CLRBIT(sc, UDAV_RCR, UDAV_RCR_ALL);
496188412Sthompsa
497188412Sthompsa	/* write hash value to the register */
498188412Sthompsa	udav_csr_write(sc, UDAV_MAR, hashtbl, sizeof(hashtbl));
499184610Salfred}
500184610Salfred
501184610Salfredstatic void
502192984Sthompsaudav_setpromisc(struct usb_ether *ue)
503184610Salfred{
504188412Sthompsa	struct udav_softc *sc = ue->ue_sc;
505194228Sthompsa	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
506184610Salfred	uint8_t rxmode;
507184610Salfred
508188412Sthompsa	rxmode = udav_csr_read1(sc, UDAV_RCR);
509184610Salfred	rxmode &= ~(UDAV_RCR_ALL | UDAV_RCR_PRMSC);
510184610Salfred
511188412Sthompsa	if (ifp->if_flags & IFF_PROMISC)
512184610Salfred		rxmode |= UDAV_RCR_ALL | UDAV_RCR_PRMSC;
513188412Sthompsa	else if (ifp->if_flags & IFF_ALLMULTI)
514184610Salfred		rxmode |= UDAV_RCR_ALL;
515184610Salfred
516184610Salfred	/* write new mode bits */
517188412Sthompsa	udav_csr_write1(sc, UDAV_RCR, rxmode);
518184610Salfred}
519184610Salfred
520184610Salfredstatic void
521192984Sthompsaudav_start(struct usb_ether *ue)
522184610Salfred{
523188412Sthompsa	struct udav_softc *sc = ue->ue_sc;
524184610Salfred
525188412Sthompsa	/*
526188412Sthompsa	 * start the USB transfers, if not already started:
527188412Sthompsa	 */
528194228Sthompsa	usbd_transfer_start(sc->sc_xfer[UDAV_INTR_DT_RD]);
529194228Sthompsa	usbd_transfer_start(sc->sc_xfer[UDAV_BULK_DT_RD]);
530194228Sthompsa	usbd_transfer_start(sc->sc_xfer[UDAV_BULK_DT_WR]);
531184610Salfred}
532184610Salfred
533184610Salfredstatic void
534192984Sthompsaudav_bulk_write_callback(struct usb_xfer *xfer)
535184610Salfred{
536184610Salfred	struct udav_softc *sc = xfer->priv_sc;
537194228Sthompsa	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
538184610Salfred	struct mbuf *m;
539188412Sthompsa	int extra_len;
540188412Sthompsa	int temp_len;
541184610Salfred	uint8_t buf[2];
542184610Salfred
543184610Salfred	switch (USB_GET_STATE(xfer)) {
544184610Salfred	case USB_ST_TRANSFERRED:
545184610Salfred		DPRINTFN(11, "transfer complete\n");
546184610Salfred		ifp->if_opackets++;
547184610Salfred
548188412Sthompsa		/* FALLTHROUGH */
549184610Salfred	case USB_ST_SETUP:
550188412Sthompsatr_setup:
551188412Sthompsa		if ((sc->sc_flags & UDAV_FLAG_LINK) == 0) {
552184610Salfred			/*
553184610Salfred			 * don't send anything if there is no link !
554184610Salfred			 */
555188412Sthompsa			return;
556184610Salfred		}
557184610Salfred		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
558184610Salfred
559188412Sthompsa		if (m == NULL)
560188412Sthompsa			return;
561188412Sthompsa		if (m->m_pkthdr.len > MCLBYTES)
562184610Salfred			m->m_pkthdr.len = MCLBYTES;
563184610Salfred		if (m->m_pkthdr.len < UDAV_MIN_FRAME_LEN) {
564184610Salfred			extra_len = UDAV_MIN_FRAME_LEN - m->m_pkthdr.len;
565184610Salfred		} else {
566184610Salfred			extra_len = 0;
567184610Salfred		}
568184610Salfred
569184610Salfred		temp_len = (m->m_pkthdr.len + extra_len);
570184610Salfred
571184610Salfred		/*
572184610Salfred		 * the frame length is specified in the first 2 bytes of the
573184610Salfred		 * buffer
574184610Salfred		 */
575184610Salfred		buf[0] = (uint8_t)(temp_len);
576184610Salfred		buf[1] = (uint8_t)(temp_len >> 8);
577184610Salfred
578184610Salfred		temp_len += 2;
579184610Salfred
580194228Sthompsa		usbd_copy_in(xfer->frbuffers, 0, buf, 2);
581184610Salfred
582194228Sthompsa		usbd_m_copy_in(xfer->frbuffers, 2,
583184610Salfred		    m, 0, m->m_pkthdr.len);
584184610Salfred
585184610Salfred		if (extra_len) {
586194228Sthompsa			usbd_frame_zero(xfer->frbuffers, temp_len - extra_len,
587184610Salfred			    extra_len);
588184610Salfred		}
589184610Salfred		/*
590184610Salfred		 * if there's a BPF listener, bounce a copy
591184610Salfred		 * of this frame to him:
592184610Salfred		 */
593184610Salfred		BPF_MTAP(ifp, m);
594184610Salfred
595184610Salfred		m_freem(m);
596184610Salfred
597184610Salfred		xfer->frlengths[0] = temp_len;
598194228Sthompsa		usbd_transfer_submit(xfer);
599184610Salfred		return;
600184610Salfred
601184610Salfred	default:			/* Error */
602184610Salfred		DPRINTFN(11, "transfer error, %s\n",
603194228Sthompsa		    usbd_errstr(xfer->error));
604184610Salfred
605188412Sthompsa		ifp->if_oerrors++;
606188412Sthompsa
607184610Salfred		if (xfer->error != USB_ERR_CANCELLED) {
608184610Salfred			/* try to clear stall first */
609188412Sthompsa			xfer->flags.stall_pipe = 1;
610188412Sthompsa			goto tr_setup;
611184610Salfred		}
612184610Salfred		return;
613184610Salfred	}
614184610Salfred}
615184610Salfred
616184610Salfredstatic void
617192984Sthompsaudav_bulk_read_callback(struct usb_xfer *xfer)
618184610Salfred{
619184610Salfred	struct udav_softc *sc = xfer->priv_sc;
620192984Sthompsa	struct usb_ether *ue = &sc->sc_ue;
621194228Sthompsa	struct ifnet *ifp = uether_getifp(ue);
622188412Sthompsa	struct udav_rxpkt stat;
623188412Sthompsa	int len;
624184610Salfred
625184610Salfred	switch (USB_GET_STATE(xfer)) {
626184610Salfred	case USB_ST_TRANSFERRED:
627184610Salfred
628188412Sthompsa		if (xfer->actlen < sizeof(stat) + ETHER_CRC_LEN) {
629184610Salfred			ifp->if_ierrors++;
630184610Salfred			goto tr_setup;
631184610Salfred		}
632194228Sthompsa		usbd_copy_out(xfer->frbuffers, 0, &stat, sizeof(stat));
633188412Sthompsa		xfer->actlen -= sizeof(stat);
634188412Sthompsa		len = min(xfer->actlen, le16toh(stat.pktlen));
635188412Sthompsa		len -= ETHER_CRC_LEN;
636184610Salfred
637188412Sthompsa		if (stat.rxstat & UDAV_RSR_LCS) {
638184610Salfred			ifp->if_collisions++;
639184610Salfred			goto tr_setup;
640184610Salfred		}
641188412Sthompsa		if (stat.rxstat & UDAV_RSR_ERR) {
642184610Salfred			ifp->if_ierrors++;
643184610Salfred			goto tr_setup;
644184610Salfred		}
645194228Sthompsa		uether_rxbuf(ue, xfer->frbuffers, sizeof(stat), len);
646188412Sthompsa		/* FALLTHROUGH */
647184610Salfred	case USB_ST_SETUP:
648184610Salfredtr_setup:
649188412Sthompsa		xfer->frlengths[0] = xfer->max_data_length;
650194228Sthompsa		usbd_transfer_submit(xfer);
651194228Sthompsa		uether_rxflush(ue);
652184610Salfred		return;
653184610Salfred
654184610Salfred	default:			/* Error */
655188412Sthompsa		DPRINTF("bulk read error, %s\n",
656194228Sthompsa		    usbd_errstr(xfer->error));
657188412Sthompsa
658184610Salfred		if (xfer->error != USB_ERR_CANCELLED) {
659184610Salfred			/* try to clear stall first */
660188412Sthompsa			xfer->flags.stall_pipe = 1;
661188412Sthompsa			goto tr_setup;
662184610Salfred		}
663184610Salfred		return;
664184610Salfred	}
665184610Salfred}
666184610Salfred
667184610Salfredstatic void
668192984Sthompsaudav_intr_callback(struct usb_xfer *xfer)
669184610Salfred{
670184610Salfred	switch (USB_GET_STATE(xfer)) {
671184610Salfred	case USB_ST_TRANSFERRED:
672184610Salfred	case USB_ST_SETUP:
673188412Sthompsatr_setup:
674188412Sthompsa		xfer->frlengths[0] = xfer->max_data_length;
675194228Sthompsa		usbd_transfer_submit(xfer);
676184610Salfred		return;
677184610Salfred
678184610Salfred	default:			/* Error */
679184610Salfred		if (xfer->error != USB_ERR_CANCELLED) {
680188412Sthompsa			/* try to clear stall first */
681188412Sthompsa			xfer->flags.stall_pipe = 1;
682188412Sthompsa			goto tr_setup;
683184610Salfred		}
684184610Salfred		return;
685184610Salfred	}
686184610Salfred}
687184610Salfred
688184610Salfredstatic void
689192984Sthompsaudav_stop(struct usb_ether *ue)
690184610Salfred{
691188412Sthompsa	struct udav_softc *sc = ue->ue_sc;
692194228Sthompsa	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
693184610Salfred
694188412Sthompsa	UDAV_LOCK_ASSERT(sc, MA_OWNED);
695184610Salfred
696188412Sthompsa	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
697188412Sthompsa	sc->sc_flags &= ~UDAV_FLAG_LINK;
698184610Salfred
699184610Salfred	/*
700184610Salfred	 * stop all the transfers, if not already stopped:
701184610Salfred	 */
702194228Sthompsa	usbd_transfer_stop(sc->sc_xfer[UDAV_BULK_DT_WR]);
703194228Sthompsa	usbd_transfer_stop(sc->sc_xfer[UDAV_BULK_DT_RD]);
704194228Sthompsa	usbd_transfer_stop(sc->sc_xfer[UDAV_INTR_DT_RD]);
705184610Salfred
706188412Sthompsa	udav_reset(sc);
707184610Salfred}
708184610Salfred
709184610Salfredstatic int
710188412Sthompsaudav_ifmedia_upd(struct ifnet *ifp)
711184610Salfred{
712184610Salfred	struct udav_softc *sc = ifp->if_softc;
713184610Salfred	struct mii_data *mii = GET_MII(sc);
714184610Salfred
715188412Sthompsa	UDAV_LOCK_ASSERT(sc, MA_OWNED);
716184610Salfred
717188412Sthompsa        sc->sc_flags &= ~UDAV_FLAG_LINK;
718184610Salfred	if (mii->mii_instance) {
719184610Salfred		struct mii_softc *miisc;
720184610Salfred
721188412Sthompsa		LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
722184610Salfred			mii_phy_reset(miisc);
723184610Salfred	}
724184610Salfred	mii_mediachg(mii);
725188412Sthompsa	return (0);
726184610Salfred}
727184610Salfred
728184610Salfredstatic void
729188412Sthompsaudav_ifmedia_status(struct ifnet *ifp, struct ifmediareq *ifmr)
730184610Salfred{
731184610Salfred	struct udav_softc *sc = ifp->if_softc;
732188412Sthompsa	struct mii_data *mii = GET_MII(sc);
733184610Salfred
734188412Sthompsa	UDAV_LOCK(sc);
735188412Sthompsa	mii_pollstat(mii);
736188412Sthompsa	UDAV_UNLOCK(sc);
737188412Sthompsa	ifmr->ifm_active = mii->mii_media_active;
738188412Sthompsa	ifmr->ifm_status = mii->mii_media_status;
739184610Salfred}
740184610Salfred
741184610Salfredstatic void
742192984Sthompsaudav_tick(struct usb_ether *ue)
743184610Salfred{
744188412Sthompsa	struct udav_softc *sc = ue->ue_sc;
745184610Salfred	struct mii_data *mii = GET_MII(sc);
746184610Salfred
747188412Sthompsa	UDAV_LOCK_ASSERT(sc, MA_OWNED);
748188412Sthompsa
749184610Salfred	mii_tick(mii);
750188412Sthompsa	if ((sc->sc_flags & UDAV_FLAG_LINK) == 0
751188412Sthompsa	    && mii->mii_media_status & IFM_ACTIVE &&
752188412Sthompsa	    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
753188412Sthompsa		sc->sc_flags |= UDAV_FLAG_LINK;
754188412Sthompsa		udav_start(ue);
755184610Salfred	}
756184610Salfred}
757184610Salfred
758184610Salfredstatic int
759188412Sthompsaudav_miibus_readreg(device_t dev, int phy, int reg)
760184610Salfred{
761184610Salfred	struct udav_softc *sc = device_get_softc(dev);
762184610Salfred	uint16_t data16;
763184610Salfred	uint8_t val[2];
764188412Sthompsa	int locked;
765184610Salfred
766184610Salfred	/* XXX: one PHY only for the internal PHY */
767188412Sthompsa	if (phy != 0)
768184610Salfred		return (0);
769184610Salfred
770188412Sthompsa	locked = mtx_owned(&sc->sc_mtx);
771188412Sthompsa	if (!locked)
772188412Sthompsa		UDAV_LOCK(sc);
773188412Sthompsa
774184610Salfred	/* select internal PHY and set PHY register address */
775188412Sthompsa	udav_csr_write1(sc, UDAV_EPAR,
776184610Salfred	    UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK));
777184610Salfred
778184610Salfred	/* select PHY operation and start read command */
779188412Sthompsa	udav_csr_write1(sc, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRR);
780184610Salfred
781184610Salfred	/* XXX: should we wait? */
782184610Salfred
783184610Salfred	/* end read command */
784188412Sthompsa	UDAV_CLRBIT(sc, UDAV_EPCR, UDAV_EPCR_ERPRR);
785184610Salfred
786184610Salfred	/* retrieve the result from data registers */
787188412Sthompsa	udav_csr_read(sc, UDAV_EPDRL, val, 2);
788184610Salfred
789184610Salfred	data16 = (val[0] | (val[1] << 8));
790184610Salfred
791184610Salfred	DPRINTFN(11, "phy=%d reg=0x%04x => 0x%04x\n",
792184610Salfred	    phy, reg, data16);
793184610Salfred
794188412Sthompsa	if (!locked)
795188412Sthompsa		UDAV_UNLOCK(sc);
796184610Salfred	return (data16);
797184610Salfred}
798184610Salfred
799184610Salfredstatic int
800188412Sthompsaudav_miibus_writereg(device_t dev, int phy, int reg, int data)
801184610Salfred{
802184610Salfred	struct udav_softc *sc = device_get_softc(dev);
803184610Salfred	uint8_t val[2];
804188412Sthompsa	int locked;
805184610Salfred
806184610Salfred	/* XXX: one PHY only for the internal PHY */
807188412Sthompsa	if (phy != 0)
808184610Salfred		return (0);
809184610Salfred
810188412Sthompsa	locked = mtx_owned(&sc->sc_mtx);
811188412Sthompsa	if (!locked)
812188412Sthompsa		UDAV_LOCK(sc);
813188412Sthompsa
814184610Salfred	/* select internal PHY and set PHY register address */
815188412Sthompsa	udav_csr_write1(sc, UDAV_EPAR,
816184610Salfred	    UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK));
817184610Salfred
818184610Salfred	/* put the value to the data registers */
819184610Salfred	val[0] = (data & 0xff);
820184610Salfred	val[1] = (data >> 8) & 0xff;
821188412Sthompsa	udav_csr_write(sc, UDAV_EPDRL, val, 2);
822184610Salfred
823184610Salfred	/* select PHY operation and start write command */
824188412Sthompsa	udav_csr_write1(sc, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRW);
825184610Salfred
826184610Salfred	/* XXX: should we wait? */
827184610Salfred
828184610Salfred	/* end write command */
829188412Sthompsa	UDAV_CLRBIT(sc, UDAV_EPCR, UDAV_EPCR_ERPRW);
830184610Salfred
831188412Sthompsa	if (!locked)
832188412Sthompsa		UDAV_UNLOCK(sc);
833184610Salfred	return (0);
834184610Salfred}
835184610Salfred
836184610Salfredstatic void
837188412Sthompsaudav_miibus_statchg(device_t dev)
838184610Salfred{
839184610Salfred	/* nothing to do */
840184610Salfred}
841