if_udav.c revision 195049
1191762Simp/*	$NetBSD: if_udav.c,v 1.2 2003/09/04 15:17:38 tsutsui Exp $	*/
2191762Simp/*	$nabe: if_udav.c,v 1.3 2003/08/21 16:57:19 nabe Exp $	*/
3191762Simp/*	$FreeBSD: head/sys/dev/usb/net/if_udav.c 195049 2009-06-26 11:45:06Z rwatson $	*/
4191762Simp/*-
5191762Simp * Copyright (c) 2003
6191762Simp *     Shingo WATANABE <nabe@nabechan.org>.  All rights reserved.
7191762Simp *
8191762Simp * Redistribution and use in source and binary forms, with or without
9191762Simp * modification, are permitted provided that the following conditions
10191762Simp * are met:
11191762Simp * 1. Redistributions of source code must retain the above copyright
12191762Simp *    notice, this list of conditions and the following disclaimer.
13191762Simp * 2. Redistributions in binary form must reproduce the above copyright
14191762Simp *    notice, this list of conditions and the following disclaimer in the
15191762Simp *    documentation and/or other materials provided with the distribution.
16191762Simp * 3. Neither the name of the author nor the names of any co-contributors
17191762Simp *    may be used to endorse or promote products derived from this software
18191762Simp *    without specific prior written permission.
19191762Simp *
20191762Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21191762Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22191762Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23191762Simp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24191762Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25191762Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26191762Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27191762Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28191762Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29191762Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30191762Simp * SUCH DAMAGE.
31191762Simp *
32191762Simp */
33191762Simp
34191762Simp/*
35191762Simp * DM9601(DAVICOM USB to Ethernet MAC Controller with Integrated 10/100 PHY)
36191762Simp * The spec can be found at the following url.
37191762Simp *   http://www.davicom.com.tw/big5/download/Data%20Sheet/DM9601-DS-P01-930914.pdf
38191762Simp */
39191762Simp
40191762Simp/*
41235338Sadrian * TODO:
42191762Simp *	Interrupt Endpoint support
43191762Simp *	External PHYs
44191762Simp */
45191762Simp
46191762Simp#include <sys/cdefs.h>
47191762Simp__FBSDID("$FreeBSD: head/sys/dev/usb/net/if_udav.c 195049 2009-06-26 11:45:06Z rwatson $");
48191762Simp
49191762Simp#include <sys/stdint.h>
50191762Simp#include <sys/stddef.h>
51191762Simp#include <sys/param.h>
52191762Simp#include <sys/queue.h>
53191762Simp#include <sys/types.h>
54191762Simp#include <sys/systm.h>
55191762Simp#include <sys/kernel.h>
56191762Simp#include <sys/bus.h>
57191762Simp#include <sys/linker_set.h>
58191762Simp#include <sys/module.h>
59191762Simp#include <sys/lock.h>
60191762Simp#include <sys/mutex.h>
61191762Simp#include <sys/condvar.h>
62191762Simp#include <sys/sysctl.h>
63191762Simp#include <sys/sx.h>
64191762Simp#include <sys/unistd.h>
65191762Simp#include <sys/callout.h>
66191762Simp#include <sys/malloc.h>
67191762Simp#include <sys/priv.h>
68191762Simp
69191762Simp#include <dev/usb/usb.h>
70191762Simp#include <dev/usb/usbdi.h>
71191762Simp#include <dev/usb/usbdi_util.h>
72191762Simp#include "usbdevs.h"
73191762Simp
74191762Simp#define	USB_DEBUG_VAR udav_debug
75191762Simp#include <dev/usb/usb_debug.h>
76191762Simp#include <dev/usb/usb_process.h>
77191762Simp
78191762Simp#include <dev/usb/net/usb_ethernet.h>
79191762Simp#include <dev/usb/net/if_udavreg.h>
80191762Simp
81191762Simp/* prototypes */
82191762Simp
83191762Simpstatic device_probe_t udav_probe;
84191762Simpstatic device_attach_t udav_attach;
85191762Simpstatic device_detach_t udav_detach;
86191762Simp
87191762Simpstatic usb_callback_t udav_bulk_write_callback;
88191762Simpstatic usb_callback_t udav_bulk_read_callback;
89191762Simpstatic usb_callback_t udav_intr_callback;
90191762Simp
91191762Simpstatic uether_fn_t udav_attach_post;
92191762Simpstatic uether_fn_t udav_init;
93191762Simpstatic uether_fn_t udav_stop;
94191762Simpstatic uether_fn_t udav_start;
95191762Simpstatic uether_fn_t udav_tick;
96191762Simpstatic uether_fn_t udav_setmulti;
97191762Simpstatic uether_fn_t udav_setpromisc;
98191762Simp
99191762Simpstatic int	udav_csr_read(struct udav_softc *, uint16_t, void *, int);
100191762Simpstatic int	udav_csr_write(struct udav_softc *, uint16_t, void *, int);
101191762Simpstatic uint8_t	udav_csr_read1(struct udav_softc *, uint16_t);
102191762Simpstatic int	udav_csr_write1(struct udav_softc *, uint16_t, uint8_t);
103191762Simpstatic void	udav_reset(struct udav_softc *);
104191762Simpstatic int	udav_ifmedia_upd(struct ifnet *);
105191762Simpstatic void	udav_ifmedia_status(struct ifnet *, struct ifmediareq *);
106191762Simp
107191762Simpstatic miibus_readreg_t udav_miibus_readreg;
108191762Simpstatic miibus_writereg_t udav_miibus_writereg;
109191762Simpstatic miibus_statchg_t udav_miibus_statchg;
110191762Simp
111191762Simpstatic const struct usb_config udav_config[UDAV_N_TRANSFER] = {
112191762Simp
113191762Simp	[UDAV_BULK_DT_WR] = {
114191762Simp		.type = UE_BULK,
115191762Simp		.endpoint = UE_ADDR_ANY,
116191762Simp		.direction = UE_DIR_OUT,
117191762Simp		.bufsize = (MCLBYTES + 2),
118191762Simp		.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
119191762Simp		.callback = udav_bulk_write_callback,
120191762Simp		.timeout = 10000,	/* 10 seconds */
121191762Simp	},
122191762Simp
123191762Simp	[UDAV_BULK_DT_RD] = {
124191762Simp		.type = UE_BULK,
125191762Simp		.endpoint = UE_ADDR_ANY,
126191762Simp		.direction = UE_DIR_IN,
127191762Simp		.bufsize = (MCLBYTES + 3),
128191762Simp		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
129191762Simp		.callback = udav_bulk_read_callback,
130191762Simp		.timeout = 0,	/* no timeout */
131191762Simp	},
132191762Simp
133191762Simp	[UDAV_INTR_DT_RD] = {
134191762Simp		.type = UE_INTERRUPT,
135191762Simp		.endpoint = UE_ADDR_ANY,
136191762Simp		.direction = UE_DIR_IN,
137191762Simp		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
138191762Simp		.bufsize = 0,	/* use wMaxPacketSize */
139191762Simp		.callback = udav_intr_callback,
140191762Simp	},
141191762Simp};
142191762Simp
143191762Simpstatic device_method_t udav_methods[] = {
144191762Simp	/* Device interface */
145191762Simp	DEVMETHOD(device_probe, udav_probe),
146191762Simp	DEVMETHOD(device_attach, udav_attach),
147191762Simp	DEVMETHOD(device_detach, udav_detach),
148191762Simp
149191762Simp	/* bus interface */
150191762Simp	DEVMETHOD(bus_print_child, bus_generic_print_child),
151191762Simp	DEVMETHOD(bus_driver_added, bus_generic_driver_added),
152191762Simp
153191762Simp	/* MII interface */
154191762Simp	DEVMETHOD(miibus_readreg, udav_miibus_readreg),
155191762Simp	DEVMETHOD(miibus_writereg, udav_miibus_writereg),
156191762Simp	DEVMETHOD(miibus_statchg, udav_miibus_statchg),
157191762Simp
158191762Simp	{0, 0}
159191762Simp};
160191762Simp
161191762Simpstatic driver_t udav_driver = {
162191762Simp	.name = "udav",
163191762Simp	.methods = udav_methods,
164191762Simp	.size = sizeof(struct udav_softc),
165191762Simp};
166191762Simp
167191762Simpstatic devclass_t udav_devclass;
168191762Simp
169191762SimpDRIVER_MODULE(udav, uhub, udav_driver, udav_devclass, NULL, 0);
170191762SimpDRIVER_MODULE(miibus, udav, miibus_driver, miibus_devclass, 0, 0);
171191762SimpMODULE_DEPEND(udav, uether, 1, 1, 1);
172191762SimpMODULE_DEPEND(udav, usb, 1, 1, 1);
173191762SimpMODULE_DEPEND(udav, ether, 1, 1, 1);
174191762SimpMODULE_DEPEND(udav, miibus, 1, 1, 1);
175191762Simp
176191762Simpstatic const struct usb_ether_methods udav_ue_methods = {
177191762Simp	.ue_attach_post = udav_attach_post,
178191762Simp	.ue_start = udav_start,
179191762Simp	.ue_init = udav_init,
180191762Simp	.ue_stop = udav_stop,
181191762Simp	.ue_tick = udav_tick,
182191762Simp	.ue_setmulti = udav_setmulti,
183191762Simp	.ue_setpromisc = udav_setpromisc,
184191762Simp	.ue_mii_upd = udav_ifmedia_upd,
185191762Simp	.ue_mii_sts = udav_ifmedia_status,
186191762Simp};
187191762Simp
188191762Simp#if USB_DEBUG
189191762Simpstatic int udav_debug = 0;
190191762Simp
191191762SimpSYSCTL_NODE(_hw_usb, OID_AUTO, udav, CTLFLAG_RW, 0, "USB udav");
192191762SimpSYSCTL_INT(_hw_usb_udav, OID_AUTO, debug, CTLFLAG_RW, &udav_debug, 0,
193191762Simp    "Debug level");
194191762Simp#endif
195191762Simp
196191762Simp#define	UDAV_SETBIT(sc, reg, x)	\
197191762Simp	udav_csr_write1(sc, reg, udav_csr_read1(sc, reg) | (x))
198191762Simp
199191762Simp#define	UDAV_CLRBIT(sc, reg, x)	\
200191762Simp	udav_csr_write1(sc, reg, udav_csr_read1(sc, reg) & ~(x))
201191762Simp
202191762Simpstatic const struct usb_device_id udav_devs[] = {
203191762Simp	/* ShanTou DM9601 USB NIC */
204191762Simp	{USB_VPI(USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_DM9601, 0)},
205191762Simp	/* ShanTou ST268 USB NIC */
206191762Simp	{USB_VPI(USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_ST268, 0)},
207191762Simp	/* Corega USB-TXC */
208191762Simp	{USB_VPI(USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TXC, 0)},
209191762Simp};
210191762Simp
211191762Simpstatic void
212191762Simpudav_attach_post(struct usb_ether *ue)
213191762Simp{
214191762Simp	struct udav_softc *sc = uether_getsc(ue);
215191762Simp
216191762Simp	/* reset the adapter */
217191762Simp	udav_reset(sc);
218191762Simp
219191762Simp	/* Get Ethernet Address */
220191762Simp	udav_csr_read(sc, UDAV_PAR, ue->ue_eaddr, ETHER_ADDR_LEN);
221191762Simp}
222191762Simp
223191762Simpstatic int
224191762Simpudav_probe(device_t dev)
225191762Simp{
226191762Simp	struct usb_attach_arg *uaa = device_get_ivars(dev);
227191762Simp
228191762Simp	if (uaa->usb_mode != USB_MODE_HOST)
229191762Simp		return (ENXIO);
230191762Simp	if (uaa->info.bConfigIndex != UDAV_CONFIG_INDEX)
231191762Simp		return (ENXIO);
232191762Simp	if (uaa->info.bIfaceIndex != UDAV_IFACE_INDEX)
233191762Simp		return (ENXIO);
234191762Simp
235191762Simp	return (usbd_lookup_id_by_uaa(udav_devs, sizeof(udav_devs), uaa));
236191762Simp}
237191762Simp
238191762Simpstatic int
239191762Simpudav_attach(device_t dev)
240191762Simp{
241191762Simp	struct usb_attach_arg *uaa = device_get_ivars(dev);
242191762Simp	struct udav_softc *sc = device_get_softc(dev);
243191762Simp	struct usb_ether *ue = &sc->sc_ue;
244191762Simp	uint8_t iface_index;
245191762Simp	int error;
246191762Simp
247191762Simp	sc->sc_flags = USB_GET_DRIVER_INFO(uaa);
248191762Simp
249191762Simp	device_set_usb_desc(dev);
250191762Simp
251191762Simp	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
252191762Simp
253191762Simp	iface_index = UDAV_IFACE_INDEX;
254191762Simp	error = usbd_transfer_setup(uaa->device, &iface_index,
255191762Simp	    sc->sc_xfer, udav_config, UDAV_N_TRANSFER, sc, &sc->sc_mtx);
256191762Simp	if (error) {
257191762Simp		device_printf(dev, "allocating USB transfers failed!\n");
258191762Simp		goto detach;
259191762Simp	}
260191762Simp
261191762Simp	ue->ue_sc = sc;
262191762Simp	ue->ue_dev = dev;
263191762Simp	ue->ue_udev = uaa->device;
264191762Simp	ue->ue_mtx = &sc->sc_mtx;
265191762Simp	ue->ue_methods = &udav_ue_methods;
266191762Simp
267191762Simp	error = uether_ifattach(ue);
268191762Simp	if (error) {
269191762Simp		device_printf(dev, "could not attach interface\n");
270191762Simp		goto detach;
271191762Simp	}
272191762Simp
273191762Simp	return (0);			/* success */
274191762Simp
275191762Simpdetach:
276191762Simp	udav_detach(dev);
277191762Simp	return (ENXIO);			/* failure */
278191762Simp}
279191762Simp
280191762Simpstatic int
281191762Simpudav_detach(device_t dev)
282191762Simp{
283191762Simp	struct udav_softc *sc = device_get_softc(dev);
284191762Simp	struct usb_ether *ue = &sc->sc_ue;
285191762Simp
286191762Simp	usbd_transfer_unsetup(sc->sc_xfer, UDAV_N_TRANSFER);
287191762Simp	uether_ifdetach(ue);
288191762Simp	mtx_destroy(&sc->sc_mtx);
289191762Simp
290191762Simp	return (0);
291191762Simp}
292191762Simp
293191762Simp#if 0
294191762Simpstatic int
295191762Simpudav_mem_read(struct udav_softc *sc, uint16_t offset, void *buf,
296191762Simp    int len)
297191762Simp{
298191762Simp	struct usb_device_request req;
299191762Simp
300191762Simp	len &= 0xff;
301191762Simp
302191762Simp	req.bmRequestType = UT_READ_VENDOR_DEVICE;
303191762Simp	req.bRequest = UDAV_REQ_MEM_READ;
304191762Simp	USETW(req.wValue, 0x0000);
305191762Simp	USETW(req.wIndex, offset);
306191762Simp	USETW(req.wLength, len);
307191762Simp
308191762Simp	return (uether_do_request(&sc->sc_ue, &req, buf, 1000));
309191762Simp}
310191762Simp
311191762Simpstatic int
312191762Simpudav_mem_write(struct udav_softc *sc, uint16_t offset, void *buf,
313191762Simp    int len)
314191762Simp{
315191762Simp	struct usb_device_request req;
316191762Simp
317191762Simp	len &= 0xff;
318191762Simp
319191762Simp	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
320191762Simp	req.bRequest = UDAV_REQ_MEM_WRITE;
321191762Simp	USETW(req.wValue, 0x0000);
322191762Simp	USETW(req.wIndex, offset);
323191762Simp	USETW(req.wLength, len);
324191762Simp
325191762Simp	return (uether_do_request(&sc->sc_ue, &req, buf, 1000));
326191762Simp}
327191762Simp
328191762Simpstatic int
329191762Simpudav_mem_write1(struct udav_softc *sc, uint16_t offset,
330191762Simp    uint8_t ch)
331191762Simp{
332191762Simp	struct usb_device_request req;
333191762Simp
334191762Simp	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
335191762Simp	req.bRequest = UDAV_REQ_MEM_WRITE1;
336191762Simp	USETW(req.wValue, ch);
337191762Simp	USETW(req.wIndex, offset);
338191762Simp	USETW(req.wLength, 0x0000);
339191762Simp
340191762Simp	return (uether_do_request(&sc->sc_ue, &req, NULL, 1000));
341191762Simp}
342191762Simp#endif
343191762Simp
344191762Simpstatic int
345191762Simpudav_csr_read(struct udav_softc *sc, uint16_t offset, void *buf, int len)
346191762Simp{
347191762Simp	struct usb_device_request req;
348191762Simp
349191762Simp	len &= 0xff;
350191762Simp
351191762Simp	req.bmRequestType = UT_READ_VENDOR_DEVICE;
352191762Simp	req.bRequest = UDAV_REQ_REG_READ;
353191762Simp	USETW(req.wValue, 0x0000);
354191762Simp	USETW(req.wIndex, offset);
355191762Simp	USETW(req.wLength, len);
356191762Simp
357191762Simp	return (uether_do_request(&sc->sc_ue, &req, buf, 1000));
358191762Simp}
359191762Simp
360191762Simpstatic int
361191762Simpudav_csr_write(struct udav_softc *sc, uint16_t offset, void *buf, int len)
362191762Simp{
363191762Simp	struct usb_device_request req;
364191762Simp
365191762Simp	offset &= 0xff;
366191762Simp	len &= 0xff;
367191762Simp
368191762Simp	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
369191762Simp	req.bRequest = UDAV_REQ_REG_WRITE;
370191762Simp	USETW(req.wValue, 0x0000);
371191762Simp	USETW(req.wIndex, offset);
372191762Simp	USETW(req.wLength, len);
373191762Simp
374191762Simp	return (uether_do_request(&sc->sc_ue, &req, buf, 1000));
375191762Simp}
376191762Simp
377192306Simpstatic uint8_t
378191762Simpudav_csr_read1(struct udav_softc *sc, uint16_t offset)
379191762Simp{
380191762Simp	uint8_t val;
381191762Simp
382191762Simp	udav_csr_read(sc, offset, &val, 1);
383191762Simp	return (val);
384191762Simp}
385191762Simp
386191762Simpstatic int
387191762Simpudav_csr_write1(struct udav_softc *sc, uint16_t offset,
388191762Simp    uint8_t ch)
389191762Simp{
390191762Simp	struct usb_device_request req;
391191762Simp
392191762Simp	offset &= 0xff;
393191762Simp
394191762Simp	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
395191762Simp	req.bRequest = UDAV_REQ_REG_WRITE1;
396191762Simp	USETW(req.wValue, ch);
397191762Simp	USETW(req.wIndex, offset);
398191762Simp	USETW(req.wLength, 0x0000);
399191762Simp
400191762Simp	return (uether_do_request(&sc->sc_ue, &req, NULL, 1000));
401191762Simp}
402191762Simp
403191762Simpstatic void
404191762Simpudav_init(struct usb_ether *ue)
405191762Simp{
406191762Simp	struct udav_softc *sc = ue->ue_sc;
407191762Simp	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
408191762Simp
409191762Simp	UDAV_LOCK_ASSERT(sc, MA_OWNED);
410191762Simp
411191762Simp	/*
412191762Simp	 * Cancel pending I/O
413191762Simp	 */
414191762Simp	udav_stop(ue);
415191762Simp
416191762Simp	/* set MAC address */
417191762Simp	udav_csr_write(sc, UDAV_PAR, IF_LLADDR(ifp), ETHER_ADDR_LEN);
418191762Simp
419191762Simp	/* initialize network control register */
420191762Simp
421191762Simp	/* disable loopback  */
422191762Simp	UDAV_CLRBIT(sc, UDAV_NCR, UDAV_NCR_LBK0 | UDAV_NCR_LBK1);
423191762Simp
424191762Simp	/* Initialize RX control register */
425191762Simp	UDAV_SETBIT(sc, UDAV_RCR, UDAV_RCR_DIS_LONG | UDAV_RCR_DIS_CRC);
426191762Simp
427191762Simp	/* load multicast filter and update promiscious mode bit */
428191762Simp	udav_setpromisc(ue);
429191762Simp
430191762Simp	/* enable RX */
431191762Simp	UDAV_SETBIT(sc, UDAV_RCR, UDAV_RCR_RXEN);
432191762Simp
433191762Simp	/* clear POWER_DOWN state of internal PHY */
434191762Simp	UDAV_SETBIT(sc, UDAV_GPCR, UDAV_GPCR_GEP_CNTL0);
435191762Simp	UDAV_CLRBIT(sc, UDAV_GPR, UDAV_GPR_GEPIO0);
436191762Simp
437191762Simp	usbd_xfer_set_stall(sc->sc_xfer[UDAV_BULK_DT_WR]);
438191762Simp
439191762Simp	ifp->if_drv_flags |= IFF_DRV_RUNNING;
440191762Simp	udav_start(ue);
441191762Simp}
442191762Simp
443191762Simpstatic void
444191762Simpudav_reset(struct udav_softc *sc)
445191762Simp{
446191762Simp	int i;
447191762Simp
448191762Simp	/* Select PHY */
449191762Simp#if 1
450191762Simp	/*
451191762Simp	 * XXX: force select internal phy.
452191762Simp	 *	external phy routines are not tested.
453191762Simp	 */
454191762Simp	UDAV_CLRBIT(sc, UDAV_NCR, UDAV_NCR_EXT_PHY);
455191762Simp#else
456191762Simp	if (sc->sc_flags & UDAV_EXT_PHY)
457191762Simp		UDAV_SETBIT(sc, UDAV_NCR, UDAV_NCR_EXT_PHY);
458191762Simp	else
459191762Simp		UDAV_CLRBIT(sc, UDAV_NCR, UDAV_NCR_EXT_PHY);
460191762Simp#endif
461191762Simp
462191762Simp	UDAV_SETBIT(sc, UDAV_NCR, UDAV_NCR_RST);
463191762Simp
464191762Simp	for (i = 0; i < UDAV_TX_TIMEOUT; i++) {
465191762Simp		if (!(udav_csr_read1(sc, UDAV_NCR) & UDAV_NCR_RST))
466191762Simp			break;
467191762Simp		if (uether_pause(&sc->sc_ue, hz / 100))
468191762Simp			break;
469191762Simp	}
470191762Simp
471191762Simp	uether_pause(&sc->sc_ue, hz / 100);
472191762Simp}
473191762Simp
474191762Simp#define	UDAV_BITS	6
475191762Simpstatic void
476191762Simpudav_setmulti(struct usb_ether *ue)
477191762Simp{
478191762Simp	struct udav_softc *sc = ue->ue_sc;
479191762Simp	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
480191762Simp	struct ifmultiaddr *ifma;
481191762Simp	uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
482191762Simp	int h = 0;
483191762Simp
484191762Simp	UDAV_LOCK_ASSERT(sc, MA_OWNED);
485191762Simp
486191762Simp	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
487191762Simp		UDAV_SETBIT(sc, UDAV_RCR, UDAV_RCR_ALL|UDAV_RCR_PRMSC);
488191762Simp		return;
489191762Simp	}
490191762Simp
491191762Simp	/* first, zot all the existing hash bits */
492191762Simp	memset(hashtbl, 0x00, sizeof(hashtbl));
493191762Simp	hashtbl[7] |= 0x80;	/* broadcast address */
494191762Simp	udav_csr_write(sc, UDAV_MAR, hashtbl, sizeof(hashtbl));
495191762Simp
496191762Simp	/* now program new ones */
497191762Simp	if_maddr_rlock(ifp);
498191762Simp	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
499191762Simp	{
500191762Simp		if (ifma->ifma_addr->sa_family != AF_LINK)
501191762Simp			continue;
502191762Simp		h = ether_crc32_be(LLADDR((struct sockaddr_dl *)
503191762Simp		    ifma->ifma_addr), ETHER_ADDR_LEN) >> 26;
504191762Simp		hashtbl[h / 8] |= 1 << (h % 8);
505191762Simp	}
506191762Simp	if_maddr_runlock(ifp);
507191762Simp
508191762Simp	/* disable all multicast */
509191762Simp	UDAV_CLRBIT(sc, UDAV_RCR, UDAV_RCR_ALL);
510191762Simp
511191762Simp	/* write hash value to the register */
512191762Simp	udav_csr_write(sc, UDAV_MAR, hashtbl, sizeof(hashtbl));
513191762Simp}
514191762Simp
515191762Simpstatic void
516191762Simpudav_setpromisc(struct usb_ether *ue)
517191762Simp{
518191762Simp	struct udav_softc *sc = ue->ue_sc;
519191762Simp	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
520191762Simp	uint8_t rxmode;
521191762Simp
522191762Simp	rxmode = udav_csr_read1(sc, UDAV_RCR);
523191762Simp	rxmode &= ~(UDAV_RCR_ALL | UDAV_RCR_PRMSC);
524191762Simp
525191762Simp	if (ifp->if_flags & IFF_PROMISC)
526191762Simp		rxmode |= UDAV_RCR_ALL | UDAV_RCR_PRMSC;
527191762Simp	else if (ifp->if_flags & IFF_ALLMULTI)
528191762Simp		rxmode |= UDAV_RCR_ALL;
529191762Simp
530191762Simp	/* write new mode bits */
531191762Simp	udav_csr_write1(sc, UDAV_RCR, rxmode);
532191762Simp}
533191762Simp
534191762Simpstatic void
535191762Simpudav_start(struct usb_ether *ue)
536191762Simp{
537191762Simp	struct udav_softc *sc = ue->ue_sc;
538191762Simp
539191762Simp	/*
540191762Simp	 * start the USB transfers, if not already started:
541191762Simp	 */
542191762Simp	usbd_transfer_start(sc->sc_xfer[UDAV_INTR_DT_RD]);
543191762Simp	usbd_transfer_start(sc->sc_xfer[UDAV_BULK_DT_RD]);
544191762Simp	usbd_transfer_start(sc->sc_xfer[UDAV_BULK_DT_WR]);
545191762Simp}
546191762Simp
547191762Simpstatic void
548191762Simpudav_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
549191762Simp{
550191762Simp	struct udav_softc *sc = usbd_xfer_softc(xfer);
551191762Simp	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
552191762Simp	struct usb_page_cache *pc;
553191762Simp	struct mbuf *m;
554191762Simp	int extra_len;
555191762Simp	int temp_len;
556191762Simp	uint8_t buf[2];
557191762Simp
558191762Simp	switch (USB_GET_STATE(xfer)) {
559191762Simp	case USB_ST_TRANSFERRED:
560191762Simp		DPRINTFN(11, "transfer complete\n");
561191762Simp		ifp->if_opackets++;
562191762Simp
563191762Simp		/* FALLTHROUGH */
564191762Simp	case USB_ST_SETUP:
565191762Simptr_setup:
566191762Simp		if ((sc->sc_flags & UDAV_FLAG_LINK) == 0) {
567191762Simp			/*
568191762Simp			 * don't send anything if there is no link !
569191762Simp			 */
570191762Simp			return;
571191762Simp		}
572191762Simp		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
573191762Simp
574191762Simp		if (m == NULL)
575191762Simp			return;
576191762Simp		if (m->m_pkthdr.len > MCLBYTES)
577191762Simp			m->m_pkthdr.len = MCLBYTES;
578191762Simp		if (m->m_pkthdr.len < UDAV_MIN_FRAME_LEN) {
579191762Simp			extra_len = UDAV_MIN_FRAME_LEN - m->m_pkthdr.len;
580191762Simp		} else {
581191762Simp			extra_len = 0;
582191762Simp		}
583191762Simp
584191762Simp		temp_len = (m->m_pkthdr.len + extra_len);
585191762Simp
586191762Simp		/*
587191762Simp		 * the frame length is specified in the first 2 bytes of the
588191762Simp		 * buffer
589191762Simp		 */
590191762Simp		buf[0] = (uint8_t)(temp_len);
591191762Simp		buf[1] = (uint8_t)(temp_len >> 8);
592191762Simp
593191762Simp		temp_len += 2;
594191762Simp
595191762Simp		pc = usbd_xfer_get_frame(xfer, 0);
596191762Simp		usbd_copy_in(pc, 0, buf, 2);
597191762Simp		usbd_m_copy_in(pc, 2, m, 0, m->m_pkthdr.len);
598191762Simp
599191762Simp		if (extra_len)
600191762Simp			usbd_frame_zero(pc, temp_len - extra_len, extra_len);
601191762Simp		/*
602191762Simp		 * if there's a BPF listener, bounce a copy
603191762Simp		 * of this frame to him:
604191762Simp		 */
605191762Simp		BPF_MTAP(ifp, m);
606191762Simp
607191762Simp		m_freem(m);
608191762Simp
609191762Simp		usbd_xfer_set_frame_len(xfer, 0, temp_len);
610191762Simp		usbd_transfer_submit(xfer);
611191762Simp		return;
612191762Simp
613191762Simp	default:			/* Error */
614191762Simp		DPRINTFN(11, "transfer error, %s\n",
615191762Simp		    usbd_errstr(error));
616191762Simp
617191762Simp		ifp->if_oerrors++;
618191762Simp
619191762Simp		if (error != USB_ERR_CANCELLED) {
620191762Simp			/* try to clear stall first */
621191762Simp			usbd_xfer_set_stall(xfer);
622191762Simp			goto tr_setup;
623191762Simp		}
624191762Simp		return;
625191762Simp	}
626191762Simp}
627191762Simp
628191762Simpstatic void
629191762Simpudav_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
630191762Simp{
631191762Simp	struct udav_softc *sc = usbd_xfer_softc(xfer);
632191762Simp	struct usb_ether *ue = &sc->sc_ue;
633191762Simp	struct ifnet *ifp = uether_getifp(ue);
634191762Simp	struct usb_page_cache *pc;
635191762Simp	struct udav_rxpkt stat;
636191762Simp	int len;
637191762Simp	int actlen;
638191762Simp
639191762Simp	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
640191762Simp
641191762Simp	switch (USB_GET_STATE(xfer)) {
642191762Simp	case USB_ST_TRANSFERRED:
643191762Simp
644191762Simp		if (actlen < sizeof(stat) + ETHER_CRC_LEN) {
645191762Simp			ifp->if_ierrors++;
646191762Simp			goto tr_setup;
647191762Simp		}
648191762Simp		pc = usbd_xfer_get_frame(xfer, 0);
649191762Simp		usbd_copy_out(pc, 0, &stat, sizeof(stat));
650191762Simp		actlen -= sizeof(stat);
651191762Simp		len = min(actlen, le16toh(stat.pktlen));
652191762Simp		len -= ETHER_CRC_LEN;
653191762Simp
654191762Simp		if (stat.rxstat & UDAV_RSR_LCS) {
655191762Simp			ifp->if_collisions++;
656191762Simp			goto tr_setup;
657191762Simp		}
658191762Simp		if (stat.rxstat & UDAV_RSR_ERR) {
659191762Simp			ifp->if_ierrors++;
660191762Simp			goto tr_setup;
661191762Simp		}
662191762Simp		uether_rxbuf(ue, pc, sizeof(stat), len);
663191762Simp		/* FALLTHROUGH */
664191762Simp	case USB_ST_SETUP:
665191762Simptr_setup:
666192046Snwhitehorn		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
667192046Snwhitehorn		usbd_transfer_submit(xfer);
668192042Snwhitehorn		uether_rxflush(ue);
669191762Simp		return;
670191762Simp
671191762Simp	default:			/* Error */
672191762Simp		DPRINTF("bulk read error, %s\n",
673191762Simp		    usbd_errstr(error));
674191762Simp
675191762Simp		if (error != USB_ERR_CANCELLED) {
676191762Simp			/* try to clear stall first */
677191762Simp			usbd_xfer_set_stall(xfer);
678191762Simp			goto tr_setup;
679191762Simp		}
680191762Simp		return;
681191762Simp	}
682191762Simp}
683191762Simp
684191762Simpstatic void
685191762Simpudav_intr_callback(struct usb_xfer *xfer, usb_error_t error)
686191762Simp{
687191762Simp	switch (USB_GET_STATE(xfer)) {
688191762Simp	case USB_ST_TRANSFERRED:
689191762Simp	case USB_ST_SETUP:
690191762Simptr_setup:
691191762Simp		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
692191762Simp		usbd_transfer_submit(xfer);
693191762Simp		return;
694191762Simp
695191762Simp	default:			/* Error */
696191762Simp		if (error != USB_ERR_CANCELLED) {
697191762Simp			/* try to clear stall first */
698191762Simp			usbd_xfer_set_stall(xfer);
699191762Simp			goto tr_setup;
700191762Simp		}
701191762Simp		return;
702191762Simp	}
703191762Simp}
704191762Simp
705191762Simpstatic void
706191762Simpudav_stop(struct usb_ether *ue)
707191762Simp{
708191762Simp	struct udav_softc *sc = ue->ue_sc;
709191762Simp	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
710191762Simp
711191762Simp	UDAV_LOCK_ASSERT(sc, MA_OWNED);
712191762Simp
713191762Simp	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
714191762Simp	sc->sc_flags &= ~UDAV_FLAG_LINK;
715191762Simp
716191762Simp	/*
717191762Simp	 * stop all the transfers, if not already stopped:
718191762Simp	 */
719191762Simp	usbd_transfer_stop(sc->sc_xfer[UDAV_BULK_DT_WR]);
720191762Simp	usbd_transfer_stop(sc->sc_xfer[UDAV_BULK_DT_RD]);
721191762Simp	usbd_transfer_stop(sc->sc_xfer[UDAV_INTR_DT_RD]);
722191762Simp
723191762Simp	udav_reset(sc);
724191762Simp}
725191762Simp
726191762Simpstatic int
727191762Simpudav_ifmedia_upd(struct ifnet *ifp)
728191762Simp{
729191762Simp	struct udav_softc *sc = ifp->if_softc;
730191762Simp	struct mii_data *mii = GET_MII(sc);
731191762Simp
732191762Simp	UDAV_LOCK_ASSERT(sc, MA_OWNED);
733191762Simp
734191762Simp        sc->sc_flags &= ~UDAV_FLAG_LINK;
735191762Simp	if (mii->mii_instance) {
736191762Simp		struct mii_softc *miisc;
737191762Simp
738191762Simp		LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
739191762Simp			mii_phy_reset(miisc);
740191762Simp	}
741191762Simp	mii_mediachg(mii);
742191762Simp	return (0);
743191762Simp}
744191762Simp
745191762Simpstatic void
746191762Simpudav_ifmedia_status(struct ifnet *ifp, struct ifmediareq *ifmr)
747191762Simp{
748191762Simp	struct udav_softc *sc = ifp->if_softc;
749191762Simp	struct mii_data *mii = GET_MII(sc);
750191762Simp
751191762Simp	UDAV_LOCK(sc);
752191762Simp	mii_pollstat(mii);
753191762Simp	UDAV_UNLOCK(sc);
754191762Simp	ifmr->ifm_active = mii->mii_media_active;
755191762Simp	ifmr->ifm_status = mii->mii_media_status;
756191762Simp}
757191762Simp
758191762Simpstatic void
759191762Simpudav_tick(struct usb_ether *ue)
760191762Simp{
761191762Simp	struct udav_softc *sc = ue->ue_sc;
762191762Simp	struct mii_data *mii = GET_MII(sc);
763191762Simp
764191762Simp	UDAV_LOCK_ASSERT(sc, MA_OWNED);
765191762Simp
766191762Simp	mii_tick(mii);
767191762Simp	if ((sc->sc_flags & UDAV_FLAG_LINK) == 0
768191762Simp	    && mii->mii_media_status & IFM_ACTIVE &&
769191762Simp	    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
770191762Simp		sc->sc_flags |= UDAV_FLAG_LINK;
771191762Simp		udav_start(ue);
772191762Simp	}
773191762Simp}
774191762Simp
775191762Simpstatic int
776191762Simpudav_miibus_readreg(device_t dev, int phy, int reg)
777191762Simp{
778191762Simp	struct udav_softc *sc = device_get_softc(dev);
779191762Simp	uint16_t data16;
780191762Simp	uint8_t val[2];
781191762Simp	int locked;
782191762Simp
783191762Simp	/* XXX: one PHY only for the internal PHY */
784191762Simp	if (phy != 0)
785191762Simp		return (0);
786191762Simp
787191762Simp	locked = mtx_owned(&sc->sc_mtx);
788191762Simp	if (!locked)
789191762Simp		UDAV_LOCK(sc);
790191762Simp
791191762Simp	/* select internal PHY and set PHY register address */
792191762Simp	udav_csr_write1(sc, UDAV_EPAR,
793191762Simp	    UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK));
794191762Simp
795191762Simp	/* select PHY operation and start read command */
796191762Simp	udav_csr_write1(sc, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRR);
797191762Simp
798191762Simp	/* XXX: should we wait? */
799191762Simp
800226182Sadrian	/* end read command */
801191762Simp	UDAV_CLRBIT(sc, UDAV_EPCR, UDAV_EPCR_ERPRR);
802191762Simp
803191762Simp	/* retrieve the result from data registers */
804191762Simp	udav_csr_read(sc, UDAV_EPDRL, val, 2);
805191762Simp
806191762Simp	data16 = (val[0] | (val[1] << 8));
807191762Simp
808191762Simp	DPRINTFN(11, "phy=%d reg=0x%04x => 0x%04x\n",
809191762Simp	    phy, reg, data16);
810191762Simp
811191762Simp	if (!locked)
812191762Simp		UDAV_UNLOCK(sc);
813191762Simp	return (data16);
814191762Simp}
815191762Simp
816191762Simpstatic int
817191762Simpudav_miibus_writereg(device_t dev, int phy, int reg, int data)
818191762Simp{
819191762Simp	struct udav_softc *sc = device_get_softc(dev);
820191762Simp	uint8_t val[2];
821191762Simp	int locked;
822191762Simp
823191762Simp	/* XXX: one PHY only for the internal PHY */
824191762Simp	if (phy != 0)
825191762Simp		return (0);
826191762Simp
827191762Simp	locked = mtx_owned(&sc->sc_mtx);
828191762Simp	if (!locked)
829191762Simp		UDAV_LOCK(sc);
830191762Simp
831191762Simp	/* select internal PHY and set PHY register address */
832191762Simp	udav_csr_write1(sc, UDAV_EPAR,
833191762Simp	    UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK));
834191762Simp
835191762Simp	/* put the value to the data registers */
836191762Simp	val[0] = (data & 0xff);
837191762Simp	val[1] = (data >> 8) & 0xff;
838191762Simp	udav_csr_write(sc, UDAV_EPDRL, val, 2);
839191762Simp
840191762Simp	/* select PHY operation and start write command */
841191762Simp	udav_csr_write1(sc, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRW);
842191762Simp
843191762Simp	/* XXX: should we wait? */
844191762Simp
845191762Simp	/* end write command */
846191762Simp	UDAV_CLRBIT(sc, UDAV_EPCR, UDAV_EPCR_ERPRW);
847191762Simp
848191762Simp	if (!locked)
849191762Simp		UDAV_UNLOCK(sc);
850191762Simp	return (0);
851191762Simp}
852191762Simp
853191762Simpstatic void
854191762Simpudav_miibus_statchg(device_t dev)
855191762Simp{
856191762Simp	/* nothing to do */
857191762Simp}
858191762Simp