if_udav.c revision 196219
1238104Sdes/*	$NetBSD: if_udav.c,v 1.2 2003/09/04 15:17:38 tsutsui Exp $	*/
2238104Sdes/*	$nabe: if_udav.c,v 1.3 2003/08/21 16:57:19 nabe Exp $	*/
3238104Sdes/*	$FreeBSD: head/sys/dev/usb/net/if_udav.c 196219 2009-08-14 20:03:53Z jhb $	*/
4238104Sdes/*-
5238104Sdes * Copyright (c) 2003
6238104Sdes *     Shingo WATANABE <nabe@nabechan.org>.  All rights reserved.
7238104Sdes *
8238104Sdes * Redistribution and use in source and binary forms, with or without
9238104Sdes * modification, are permitted provided that the following conditions
10238104Sdes * are met:
11238104Sdes * 1. Redistributions of source code must retain the above copyright
12238104Sdes *    notice, this list of conditions and the following disclaimer.
13238104Sdes * 2. Redistributions in binary form must reproduce the above copyright
14238104Sdes *    notice, this list of conditions and the following disclaimer in the
15238104Sdes *    documentation and/or other materials provided with the distribution.
16238104Sdes * 3. Neither the name of the author nor the names of any co-contributors
17238104Sdes *    may be used to endorse or promote products derived from this software
18238104Sdes *    without specific prior written permission.
19238104Sdes *
20238104Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21238104Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22238104Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23238104Sdes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24238104Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25238104Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26246854Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27238104Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28238104Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29238104Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30238104Sdes * SUCH DAMAGE.
31238104Sdes *
32238104Sdes */
33238104Sdes
34238104Sdes/*
35238104Sdes * DM9601(DAVICOM USB to Ethernet MAC Controller with Integrated 10/100 PHY)
36238104Sdes * The spec can be found at the following url.
37238104Sdes *   http://www.davicom.com.tw/big5/download/Data%20Sheet/DM9601-DS-P01-930914.pdf
38238104Sdes */
39238104Sdes
40238104Sdes/*
41238104Sdes * TODO:
42238104Sdes *	Interrupt Endpoint support
43238104Sdes *	External PHYs
44238104Sdes */
45246854Sdes
46238104Sdes#include <sys/cdefs.h>
47238104Sdes__FBSDID("$FreeBSD: head/sys/dev/usb/net/if_udav.c 196219 2009-08-14 20:03:53Z jhb $");
48238104Sdes
49238104Sdes#include <sys/stdint.h>
50238104Sdes#include <sys/stddef.h>
51238104Sdes#include <sys/param.h>
52238104Sdes#include <sys/queue.h>
53238104Sdes#include <sys/types.h>
54238104Sdes#include <sys/systm.h>
55238104Sdes#include <sys/kernel.h>
56238104Sdes#include <sys/bus.h>
57238104Sdes#include <sys/linker_set.h>
58238104Sdes#include <sys/module.h>
59238104Sdes#include <sys/lock.h>
60238104Sdes#include <sys/mutex.h>
61238104Sdes#include <sys/condvar.h>
62238104Sdes#include <sys/sysctl.h>
63238104Sdes#include <sys/sx.h>
64238104Sdes#include <sys/unistd.h>
65246854Sdes#include <sys/callout.h>
66238104Sdes#include <sys/malloc.h>
67238104Sdes#include <sys/priv.h>
68238104Sdes
69238104Sdes#include <dev/usb/usb.h>
70246854Sdes#include <dev/usb/usbdi.h>
71238104Sdes#include <dev/usb/usbdi_util.h>
72238104Sdes#include "usbdevs.h"
73238104Sdes
74238104Sdes#define	USB_DEBUG_VAR udav_debug
75238104Sdes#include <dev/usb/usb_debug.h>
76238104Sdes#include <dev/usb/usb_process.h>
77238104Sdes
78246854Sdes#include <dev/usb/net/usb_ethernet.h>
79238104Sdes#include <dev/usb/net/if_udavreg.h>
80246854Sdes
81246854Sdes/* prototypes */
82238104Sdes
83238104Sdesstatic device_probe_t udav_probe;
84238104Sdesstatic device_attach_t udav_attach;
85238104Sdesstatic device_detach_t udav_detach;
86246854Sdes
87246854Sdesstatic usb_callback_t udav_bulk_write_callback;
88238104Sdesstatic usb_callback_t udav_bulk_read_callback;
89238104Sdesstatic usb_callback_t udav_intr_callback;
90238104Sdes
91238104Sdesstatic uether_fn_t udav_attach_post;
92238104Sdesstatic uether_fn_t udav_init;
93238104Sdesstatic uether_fn_t udav_stop;
94238104Sdesstatic uether_fn_t udav_start;
95238104Sdesstatic uether_fn_t udav_tick;
96238104Sdesstatic uether_fn_t udav_setmulti;
97238104Sdesstatic uether_fn_t udav_setpromisc;
98238104Sdes
99238104Sdesstatic int	udav_csr_read(struct udav_softc *, uint16_t, void *, int);
100238104Sdesstatic int	udav_csr_write(struct udav_softc *, uint16_t, void *, int);
101238104Sdesstatic uint8_t	udav_csr_read1(struct udav_softc *, uint16_t);
102238104Sdesstatic int	udav_csr_write1(struct udav_softc *, uint16_t, uint8_t);
103238104Sdesstatic void	udav_reset(struct udav_softc *);
104238104Sdesstatic int	udav_ifmedia_upd(struct ifnet *);
105238104Sdesstatic void	udav_ifmedia_status(struct ifnet *, struct ifmediareq *);
106238104Sdes
107238104Sdesstatic miibus_readreg_t udav_miibus_readreg;
108238104Sdesstatic miibus_writereg_t udav_miibus_writereg;
109238104Sdesstatic miibus_statchg_t udav_miibus_statchg;
110238104Sdes
111238104Sdesstatic const struct usb_config udav_config[UDAV_N_TRANSFER] = {
112238104Sdes
113238104Sdes	[UDAV_BULK_DT_WR] = {
114238104Sdes		.type = UE_BULK,
115238104Sdes		.endpoint = UE_ADDR_ANY,
116238104Sdes		.direction = UE_DIR_OUT,
117238104Sdes		.bufsize = (MCLBYTES + 2),
118238104Sdes		.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
119238104Sdes		.callback = udav_bulk_write_callback,
120238104Sdes		.timeout = 10000,	/* 10 seconds */
121238104Sdes	},
122238104Sdes
123238104Sdes	[UDAV_BULK_DT_RD] = {
124238104Sdes		.type = UE_BULK,
125238104Sdes		.endpoint = UE_ADDR_ANY,
126238104Sdes		.direction = UE_DIR_IN,
127238104Sdes		.bufsize = (MCLBYTES + 3),
128238104Sdes		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
129238104Sdes		.callback = udav_bulk_read_callback,
130238104Sdes		.timeout = 0,	/* no timeout */
131238104Sdes	},
132238104Sdes
133238104Sdes	[UDAV_INTR_DT_RD] = {
134238104Sdes		.type = UE_INTERRUPT,
135238104Sdes		.endpoint = UE_ADDR_ANY,
136238104Sdes		.direction = UE_DIR_IN,
137238104Sdes		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
138238104Sdes		.bufsize = 0,	/* use wMaxPacketSize */
139238104Sdes		.callback = udav_intr_callback,
140238104Sdes	},
141238104Sdes};
142238104Sdes
143238104Sdesstatic device_method_t udav_methods[] = {
144238104Sdes	/* Device interface */
145238104Sdes	DEVMETHOD(device_probe, udav_probe),
146238104Sdes	DEVMETHOD(device_attach, udav_attach),
147246854Sdes	DEVMETHOD(device_detach, udav_detach),
148238104Sdes
149238104Sdes	/* bus interface */
150238104Sdes	DEVMETHOD(bus_print_child, bus_generic_print_child),
151238104Sdes	DEVMETHOD(bus_driver_added, bus_generic_driver_added),
152238104Sdes
153238104Sdes	/* MII interface */
154238104Sdes	DEVMETHOD(miibus_readreg, udav_miibus_readreg),
155238104Sdes	DEVMETHOD(miibus_writereg, udav_miibus_writereg),
156238104Sdes	DEVMETHOD(miibus_statchg, udav_miibus_statchg),
157246854Sdes
158238104Sdes	{0, 0}
159238104Sdes};
160238104Sdes
161238104Sdesstatic driver_t udav_driver = {
162238104Sdes	.name = "udav",
163238104Sdes	.methods = udav_methods,
164238104Sdes	.size = sizeof(struct udav_softc),
165238104Sdes};
166238104Sdes
167238104Sdesstatic devclass_t udav_devclass;
168238104Sdes
169238104SdesDRIVER_MODULE(udav, uhub, udav_driver, udav_devclass, NULL, 0);
170238104SdesDRIVER_MODULE(miibus, udav, miibus_driver, miibus_devclass, 0, 0);
171238104SdesMODULE_DEPEND(udav, uether, 1, 1, 1);
172238104SdesMODULE_DEPEND(udav, usb, 1, 1, 1);
173238104SdesMODULE_DEPEND(udav, ether, 1, 1, 1);
174238104SdesMODULE_DEPEND(udav, miibus, 1, 1, 1);
175238104Sdes
176246854Sdesstatic const struct usb_ether_methods udav_ue_methods = {
177246854Sdes	.ue_attach_post = udav_attach_post,
178246854Sdes	.ue_start = udav_start,
179246854Sdes	.ue_init = udav_init,
180238104Sdes	.ue_stop = udav_stop,
181238104Sdes	.ue_tick = udav_tick,
182238104Sdes	.ue_setmulti = udav_setmulti,
183246854Sdes	.ue_setpromisc = udav_setpromisc,
184238104Sdes	.ue_mii_upd = udav_ifmedia_upd,
185238104Sdes	.ue_mii_sts = udav_ifmedia_status,
186238104Sdes};
187246854Sdes
188238104Sdes#if USB_DEBUG
189246854Sdesstatic int udav_debug = 0;
190246854Sdes
191246854SdesSYSCTL_NODE(_hw_usb, OID_AUTO, udav, CTLFLAG_RW, 0, "USB udav");
192246854SdesSYSCTL_INT(_hw_usb_udav, OID_AUTO, debug, CTLFLAG_RW, &udav_debug, 0,
193238104Sdes    "Debug level");
194238104Sdes#endif
195238104Sdes
196238104Sdes#define	UDAV_SETBIT(sc, reg, x)	\
197238104Sdes	udav_csr_write1(sc, reg, udav_csr_read1(sc, reg) | (x))
198238104Sdes
199238104Sdes#define	UDAV_CLRBIT(sc, reg, x)	\
200238104Sdes	udav_csr_write1(sc, reg, udav_csr_read1(sc, reg) & ~(x))
201238104Sdes
202238104Sdesstatic const struct usb_device_id udav_devs[] = {
203238104Sdes	/* ShanTou DM9601 USB NIC */
204246854Sdes	{USB_VPI(USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_DM9601, 0)},
205238104Sdes	/* ShanTou ST268 USB NIC */
206238104Sdes	{USB_VPI(USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_ST268, 0)},
207238104Sdes	/* Corega USB-TXC */
208238104Sdes	{USB_VPI(USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TXC, 0)},
209238104Sdes};
210238104Sdes
211238104Sdesstatic void
212238104Sdesudav_attach_post(struct usb_ether *ue)
213238104Sdes{
214238104Sdes	struct udav_softc *sc = uether_getsc(ue);
215246854Sdes
216238104Sdes	/* reset the adapter */
217238104Sdes	udav_reset(sc);
218238104Sdes
219238104Sdes	/* Get Ethernet Address */
220238104Sdes	udav_csr_read(sc, UDAV_PAR, ue->ue_eaddr, ETHER_ADDR_LEN);
221238104Sdes}
222238104Sdes
223238104Sdesstatic int
224238104Sdesudav_probe(device_t dev)
225238104Sdes{
226238104Sdes	struct usb_attach_arg *uaa = device_get_ivars(dev);
227238104Sdes
228238104Sdes	if (uaa->usb_mode != USB_MODE_HOST)
229238104Sdes		return (ENXIO);
230238104Sdes	if (uaa->info.bConfigIndex != UDAV_CONFIG_INDEX)
231238104Sdes		return (ENXIO);
232238104Sdes	if (uaa->info.bIfaceIndex != UDAV_IFACE_INDEX)
233238104Sdes		return (ENXIO);
234238104Sdes
235238104Sdes	return (usbd_lookup_id_by_uaa(udav_devs, sizeof(udav_devs), uaa));
236238104Sdes}
237238104Sdes
238238104Sdesstatic int
239238104Sdesudav_attach(device_t dev)
240238104Sdes{
241238104Sdes	struct usb_attach_arg *uaa = device_get_ivars(dev);
242238104Sdes	struct udav_softc *sc = device_get_softc(dev);
243238104Sdes	struct usb_ether *ue = &sc->sc_ue;
244238104Sdes	uint8_t iface_index;
245246854Sdes	int error;
246238104Sdes
247238104Sdes	sc->sc_flags = USB_GET_DRIVER_INFO(uaa);
248246854Sdes
249238104Sdes	device_set_usb_desc(dev);
250238104Sdes
251238104Sdes	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
252238104Sdes
253238104Sdes	iface_index = UDAV_IFACE_INDEX;
254238104Sdes	error = usbd_transfer_setup(uaa->device, &iface_index,
255238104Sdes	    sc->sc_xfer, udav_config, UDAV_N_TRANSFER, sc, &sc->sc_mtx);
256238104Sdes	if (error) {
257238104Sdes		device_printf(dev, "allocating USB transfers failed!\n");
258238104Sdes		goto detach;
259238104Sdes	}
260238104Sdes
261238104Sdes	ue->ue_sc = sc;
262238104Sdes	ue->ue_dev = dev;
263238104Sdes	ue->ue_udev = uaa->device;
264238104Sdes	ue->ue_mtx = &sc->sc_mtx;
265238104Sdes	ue->ue_methods = &udav_ue_methods;
266238104Sdes
267238104Sdes	error = uether_ifattach(ue);
268238104Sdes	if (error) {
269238104Sdes		device_printf(dev, "could not attach interface\n");
270238104Sdes		goto detach;
271238104Sdes	}
272238104Sdes
273238104Sdes	return (0);			/* success */
274238104Sdes
275238104Sdesdetach:
276238104Sdes	udav_detach(dev);
277238104Sdes	return (ENXIO);			/* failure */
278238104Sdes}
279238104Sdes
280238104Sdesstatic int
281238104Sdesudav_detach(device_t dev)
282238104Sdes{
283238104Sdes	struct udav_softc *sc = device_get_softc(dev);
284238104Sdes	struct usb_ether *ue = &sc->sc_ue;
285238104Sdes
286238104Sdes	usbd_transfer_unsetup(sc->sc_xfer, UDAV_N_TRANSFER);
287238104Sdes	uether_ifdetach(ue);
288238104Sdes	mtx_destroy(&sc->sc_mtx);
289238104Sdes
290238104Sdes	return (0);
291238104Sdes}
292238104Sdes
293238104Sdes#if 0
294238104Sdesstatic int
295238104Sdesudav_mem_read(struct udav_softc *sc, uint16_t offset, void *buf,
296238104Sdes    int len)
297238104Sdes{
298238104Sdes	struct usb_device_request req;
299238104Sdes
300238104Sdes	len &= 0xff;
301238104Sdes
302238104Sdes	req.bmRequestType = UT_READ_VENDOR_DEVICE;
303238104Sdes	req.bRequest = UDAV_REQ_MEM_READ;
304238104Sdes	USETW(req.wValue, 0x0000);
305238104Sdes	USETW(req.wIndex, offset);
306238104Sdes	USETW(req.wLength, len);
307238104Sdes
308238104Sdes	return (uether_do_request(&sc->sc_ue, &req, buf, 1000));
309238104Sdes}
310238104Sdes
311238104Sdesstatic int
312238104Sdesudav_mem_write(struct udav_softc *sc, uint16_t offset, void *buf,
313238104Sdes    int len)
314238104Sdes{
315238104Sdes	struct usb_device_request req;
316238104Sdes
317238104Sdes	len &= 0xff;
318238104Sdes
319238104Sdes	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
320238104Sdes	req.bRequest = UDAV_REQ_MEM_WRITE;
321238104Sdes	USETW(req.wValue, 0x0000);
322238104Sdes	USETW(req.wIndex, offset);
323238104Sdes	USETW(req.wLength, len);
324238104Sdes
325238104Sdes	return (uether_do_request(&sc->sc_ue, &req, buf, 1000));
326238104Sdes}
327238104Sdes
328238104Sdesstatic int
329238104Sdesudav_mem_write1(struct udav_softc *sc, uint16_t offset,
330238104Sdes    uint8_t ch)
331238104Sdes{
332238104Sdes	struct usb_device_request req;
333238104Sdes
334238104Sdes	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
335238104Sdes	req.bRequest = UDAV_REQ_MEM_WRITE1;
336238104Sdes	USETW(req.wValue, ch);
337238104Sdes	USETW(req.wIndex, offset);
338238104Sdes	USETW(req.wLength, 0x0000);
339246854Sdes
340238104Sdes	return (uether_do_request(&sc->sc_ue, &req, NULL, 1000));
341238104Sdes}
342238104Sdes#endif
343238104Sdes
344238104Sdesstatic int
345238104Sdesudav_csr_read(struct udav_softc *sc, uint16_t offset, void *buf, int len)
346238104Sdes{
347238104Sdes	struct usb_device_request req;
348238104Sdes
349238104Sdes	len &= 0xff;
350238104Sdes
351238104Sdes	req.bmRequestType = UT_READ_VENDOR_DEVICE;
352238104Sdes	req.bRequest = UDAV_REQ_REG_READ;
353238104Sdes	USETW(req.wValue, 0x0000);
354238104Sdes	USETW(req.wIndex, offset);
355238104Sdes	USETW(req.wLength, len);
356238104Sdes
357238104Sdes	return (uether_do_request(&sc->sc_ue, &req, buf, 1000));
358238104Sdes}
359238104Sdes
360238104Sdesstatic int
361238104Sdesudav_csr_write(struct udav_softc *sc, uint16_t offset, void *buf, int len)
362238104Sdes{
363238104Sdes	struct usb_device_request req;
364238104Sdes
365238104Sdes	offset &= 0xff;
366238104Sdes	len &= 0xff;
367238104Sdes
368238104Sdes	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
369238104Sdes	req.bRequest = UDAV_REQ_REG_WRITE;
370238104Sdes	USETW(req.wValue, 0x0000);
371238104Sdes	USETW(req.wIndex, offset);
372246854Sdes	USETW(req.wLength, len);
373246854Sdes
374238104Sdes	return (uether_do_request(&sc->sc_ue, &req, buf, 1000));
375238104Sdes}
376238104Sdes
377238104Sdesstatic uint8_t
378238104Sdesudav_csr_read1(struct udav_softc *sc, uint16_t offset)
379238104Sdes{
380238104Sdes	uint8_t val;
381238104Sdes
382238104Sdes	udav_csr_read(sc, offset, &val, 1);
383238104Sdes	return (val);
384238104Sdes}
385238104Sdes
386238104Sdesstatic int
387238104Sdesudav_csr_write1(struct udav_softc *sc, uint16_t offset,
388238104Sdes    uint8_t ch)
389238104Sdes{
390238104Sdes	struct usb_device_request req;
391238104Sdes
392238104Sdes	offset &= 0xff;
393238104Sdes
394238104Sdes	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
395238104Sdes	req.bRequest = UDAV_REQ_REG_WRITE1;
396238104Sdes	USETW(req.wValue, ch);
397238104Sdes	USETW(req.wIndex, offset);
398238104Sdes	USETW(req.wLength, 0x0000);
399238104Sdes
400238104Sdes	return (uether_do_request(&sc->sc_ue, &req, NULL, 1000));
401238104Sdes}
402238104Sdes
403238104Sdesstatic void
404238104Sdesudav_init(struct usb_ether *ue)
405238104Sdes{
406238104Sdes	struct udav_softc *sc = ue->ue_sc;
407238104Sdes	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
408238104Sdes
409238104Sdes	UDAV_LOCK_ASSERT(sc, MA_OWNED);
410238104Sdes
411238104Sdes	/*
412238104Sdes	 * Cancel pending I/O
413238104Sdes	 */
414238104Sdes	udav_stop(ue);
415238104Sdes
416238104Sdes	/* set MAC address */
417238104Sdes	udav_csr_write(sc, UDAV_PAR, IF_LLADDR(ifp), ETHER_ADDR_LEN);
418238104Sdes
419238104Sdes	/* initialize network control register */
420238104Sdes
421238104Sdes	/* disable loopback  */
422238104Sdes	UDAV_CLRBIT(sc, UDAV_NCR, UDAV_NCR_LBK0 | UDAV_NCR_LBK1);
423238104Sdes
424238104Sdes	/* Initialize RX control register */
425238104Sdes	UDAV_SETBIT(sc, UDAV_RCR, UDAV_RCR_DIS_LONG | UDAV_RCR_DIS_CRC);
426238104Sdes
427238104Sdes	/* load multicast filter and update promiscious mode bit */
428238104Sdes	udav_setpromisc(ue);
429238104Sdes
430238104Sdes	/* enable RX */
431238104Sdes	UDAV_SETBIT(sc, UDAV_RCR, UDAV_RCR_RXEN);
432238104Sdes
433238104Sdes	/* clear POWER_DOWN state of internal PHY */
434238104Sdes	UDAV_SETBIT(sc, UDAV_GPCR, UDAV_GPCR_GEP_CNTL0);
435238104Sdes	UDAV_CLRBIT(sc, UDAV_GPR, UDAV_GPR_GEPIO0);
436238104Sdes
437238104Sdes	usbd_xfer_set_stall(sc->sc_xfer[UDAV_BULK_DT_WR]);
438238104Sdes
439238104Sdes	ifp->if_drv_flags |= IFF_DRV_RUNNING;
440238104Sdes	udav_start(ue);
441238104Sdes}
442238104Sdes
443238104Sdesstatic void
444238104Sdesudav_reset(struct udav_softc *sc)
445238104Sdes{
446238104Sdes	int i;
447238104Sdes
448238104Sdes	/* Select PHY */
449238104Sdes#if 1
450238104Sdes	/*
451238104Sdes	 * XXX: force select internal phy.
452238104Sdes	 *	external phy routines are not tested.
453238104Sdes	 */
454238104Sdes	UDAV_CLRBIT(sc, UDAV_NCR, UDAV_NCR_EXT_PHY);
455238104Sdes#else
456238104Sdes	if (sc->sc_flags & UDAV_EXT_PHY)
457238104Sdes		UDAV_SETBIT(sc, UDAV_NCR, UDAV_NCR_EXT_PHY);
458238104Sdes	else
459246854Sdes		UDAV_CLRBIT(sc, UDAV_NCR, UDAV_NCR_EXT_PHY);
460238104Sdes#endif
461238104Sdes
462238104Sdes	UDAV_SETBIT(sc, UDAV_NCR, UDAV_NCR_RST);
463238104Sdes
464238104Sdes	for (i = 0; i < UDAV_TX_TIMEOUT; i++) {
465238104Sdes		if (!(udav_csr_read1(sc, UDAV_NCR) & UDAV_NCR_RST))
466238104Sdes			break;
467238104Sdes		if (uether_pause(&sc->sc_ue, hz / 100))
468238104Sdes			break;
469238104Sdes	}
470238104Sdes
471238104Sdes	uether_pause(&sc->sc_ue, hz / 100);
472238104Sdes}
473238104Sdes
474238104Sdes#define	UDAV_BITS	6
475238104Sdesstatic void
476238104Sdesudav_setmulti(struct usb_ether *ue)
477238104Sdes{
478246854Sdes	struct udav_softc *sc = ue->ue_sc;
479246854Sdes	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
480246854Sdes	struct ifmultiaddr *ifma;
481246854Sdes	uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
482246854Sdes	int h = 0;
483246854Sdes
484238104Sdes	UDAV_LOCK_ASSERT(sc, MA_OWNED);
485238104Sdes
486246854Sdes	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
487246854Sdes		UDAV_SETBIT(sc, UDAV_RCR, UDAV_RCR_ALL|UDAV_RCR_PRMSC);
488246854Sdes		return;
489246854Sdes	}
490246854Sdes
491246854Sdes	/* first, zot all the existing hash bits */
492238104Sdes	memset(hashtbl, 0x00, sizeof(hashtbl));
493238104Sdes	hashtbl[7] |= 0x80;	/* broadcast address */
494246854Sdes	udav_csr_write(sc, UDAV_MAR, hashtbl, sizeof(hashtbl));
495246854Sdes
496246854Sdes	/* now program new ones */
497246854Sdes	if_maddr_rlock(ifp);
498246854Sdes	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
499246854Sdes	{
500238104Sdes		if (ifma->ifma_addr->sa_family != AF_LINK)
501238104Sdes			continue;
502246854Sdes		h = ether_crc32_be(LLADDR((struct sockaddr_dl *)
503246854Sdes		    ifma->ifma_addr), ETHER_ADDR_LEN) >> 26;
504246854Sdes		hashtbl[h / 8] |= 1 << (h % 8);
505246854Sdes	}
506246854Sdes	if_maddr_runlock(ifp);
507246854Sdes
508238104Sdes	/* disable all multicast */
509238104Sdes	UDAV_CLRBIT(sc, UDAV_RCR, UDAV_RCR_ALL);
510246854Sdes
511246854Sdes	/* write hash value to the register */
512246854Sdes	udav_csr_write(sc, UDAV_MAR, hashtbl, sizeof(hashtbl));
513246854Sdes}
514246854Sdes
515246854Sdesstatic void
516238104Sdesudav_setpromisc(struct usb_ether *ue)
517238104Sdes{
518246854Sdes	struct udav_softc *sc = ue->ue_sc;
519246854Sdes	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
520246854Sdes	uint8_t rxmode;
521246854Sdes
522246854Sdes	rxmode = udav_csr_read1(sc, UDAV_RCR);
523246854Sdes	rxmode &= ~(UDAV_RCR_ALL | UDAV_RCR_PRMSC);
524238104Sdes
525238104Sdes	if (ifp->if_flags & IFF_PROMISC)
526246854Sdes		rxmode |= UDAV_RCR_ALL | UDAV_RCR_PRMSC;
527246854Sdes	else if (ifp->if_flags & IFF_ALLMULTI)
528246854Sdes		rxmode |= UDAV_RCR_ALL;
529246854Sdes
530246854Sdes	/* write new mode bits */
531246854Sdes	udav_csr_write1(sc, UDAV_RCR, rxmode);
532238104Sdes}
533238104Sdes
534246854Sdesstatic void
535246854Sdesudav_start(struct usb_ether *ue)
536246854Sdes{
537246854Sdes	struct udav_softc *sc = ue->ue_sc;
538246854Sdes
539246854Sdes	/*
540246854Sdes	 * start the USB transfers, if not already started:
541238104Sdes	 */
542238104Sdes	usbd_transfer_start(sc->sc_xfer[UDAV_INTR_DT_RD]);
543246854Sdes	usbd_transfer_start(sc->sc_xfer[UDAV_BULK_DT_RD]);
544246854Sdes	usbd_transfer_start(sc->sc_xfer[UDAV_BULK_DT_WR]);
545246854Sdes}
546246854Sdes
547246854Sdesstatic void
548246854Sdesudav_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
549238104Sdes{
550238104Sdes	struct udav_softc *sc = usbd_xfer_softc(xfer);
551246854Sdes	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
552246854Sdes	struct usb_page_cache *pc;
553246854Sdes	struct mbuf *m;
554246854Sdes	int extra_len;
555246854Sdes	int temp_len;
556246854Sdes	uint8_t buf[2];
557238104Sdes
558238104Sdes	switch (USB_GET_STATE(xfer)) {
559246854Sdes	case USB_ST_TRANSFERRED:
560246854Sdes		DPRINTFN(11, "transfer complete\n");
561246854Sdes		ifp->if_opackets++;
562246854Sdes
563246854Sdes		/* FALLTHROUGH */
564246854Sdes	case USB_ST_SETUP:
565238104Sdestr_setup:
566238104Sdes		if ((sc->sc_flags & UDAV_FLAG_LINK) == 0) {
567246854Sdes			/*
568246854Sdes			 * don't send anything if there is no link !
569246854Sdes			 */
570246854Sdes			return;
571246854Sdes		}
572246854Sdes		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
573238104Sdes
574238104Sdes		if (m == NULL)
575246854Sdes			return;
576246854Sdes		if (m->m_pkthdr.len > MCLBYTES)
577246854Sdes			m->m_pkthdr.len = MCLBYTES;
578246854Sdes		if (m->m_pkthdr.len < UDAV_MIN_FRAME_LEN) {
579246854Sdes			extra_len = UDAV_MIN_FRAME_LEN - m->m_pkthdr.len;
580246854Sdes		} else {
581238104Sdes			extra_len = 0;
582238104Sdes		}
583246854Sdes
584246854Sdes		temp_len = (m->m_pkthdr.len + extra_len);
585246854Sdes
586246854Sdes		/*
587246854Sdes		 * the frame length is specified in the first 2 bytes of the
588246854Sdes		 * buffer
589238104Sdes		 */
590238104Sdes		buf[0] = (uint8_t)(temp_len);
591246854Sdes		buf[1] = (uint8_t)(temp_len >> 8);
592246854Sdes
593246854Sdes		temp_len += 2;
594246854Sdes
595246854Sdes		pc = usbd_xfer_get_frame(xfer, 0);
596246854Sdes		usbd_copy_in(pc, 0, buf, 2);
597238104Sdes		usbd_m_copy_in(pc, 2, m, 0, m->m_pkthdr.len);
598238104Sdes
599246854Sdes		if (extra_len)
600246854Sdes			usbd_frame_zero(pc, temp_len - extra_len, extra_len);
601246854Sdes		/*
602246854Sdes		 * if there's a BPF listener, bounce a copy
603246854Sdes		 * of this frame to him:
604246854Sdes		 */
605238104Sdes		BPF_MTAP(ifp, m);
606238104Sdes
607246854Sdes		m_freem(m);
608246854Sdes
609246854Sdes		usbd_xfer_set_frame_len(xfer, 0, temp_len);
610246854Sdes		usbd_transfer_submit(xfer);
611246854Sdes		return;
612246854Sdes
613246854Sdes	default:			/* Error */
614238104Sdes		DPRINTFN(11, "transfer error, %s\n",
615238104Sdes		    usbd_errstr(error));
616246854Sdes
617246854Sdes		ifp->if_oerrors++;
618246854Sdes
619246854Sdes		if (error != USB_ERR_CANCELLED) {
620246854Sdes			/* try to clear stall first */
621246854Sdes			usbd_xfer_set_stall(xfer);
622238104Sdes			goto tr_setup;
623238104Sdes		}
624246854Sdes		return;
625246854Sdes	}
626246854Sdes}
627246854Sdes
628246854Sdesstatic void
629246854Sdesudav_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
630238104Sdes{
631238104Sdes	struct udav_softc *sc = usbd_xfer_softc(xfer);
632246854Sdes	struct usb_ether *ue = &sc->sc_ue;
633246854Sdes	struct ifnet *ifp = uether_getifp(ue);
634246854Sdes	struct usb_page_cache *pc;
635246854Sdes	struct udav_rxpkt stat;
636246854Sdes	int len;
637246854Sdes	int actlen;
638238104Sdes
639238104Sdes	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
640246854Sdes
641246854Sdes	switch (USB_GET_STATE(xfer)) {
642246854Sdes	case USB_ST_TRANSFERRED:
643246854Sdes
644246854Sdes		if (actlen < sizeof(stat) + ETHER_CRC_LEN) {
645246854Sdes			ifp->if_ierrors++;
646238104Sdes			goto tr_setup;
647238104Sdes		}
648246854Sdes		pc = usbd_xfer_get_frame(xfer, 0);
649246854Sdes		usbd_copy_out(pc, 0, &stat, sizeof(stat));
650246854Sdes		actlen -= sizeof(stat);
651246854Sdes		len = min(actlen, le16toh(stat.pktlen));
652246854Sdes		len -= ETHER_CRC_LEN;
653246854Sdes
654246854Sdes		if (stat.rxstat & UDAV_RSR_LCS) {
655238104Sdes			ifp->if_collisions++;
656238104Sdes			goto tr_setup;
657246854Sdes		}
658246854Sdes		if (stat.rxstat & UDAV_RSR_ERR) {
659246854Sdes			ifp->if_ierrors++;
660246854Sdes			goto tr_setup;
661246854Sdes		}
662246854Sdes		uether_rxbuf(ue, pc, sizeof(stat), len);
663238104Sdes		/* FALLTHROUGH */
664238104Sdes	case USB_ST_SETUP:
665246854Sdestr_setup:
666246854Sdes		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
667246854Sdes		usbd_transfer_submit(xfer);
668246854Sdes		uether_rxflush(ue);
669246854Sdes		return;
670246854Sdes
671238104Sdes	default:			/* Error */
672238104Sdes		DPRINTF("bulk read error, %s\n",
673246854Sdes		    usbd_errstr(error));
674246854Sdes
675246854Sdes		if (error != USB_ERR_CANCELLED) {
676246854Sdes			/* try to clear stall first */
677246854Sdes			usbd_xfer_set_stall(xfer);
678246854Sdes			goto tr_setup;
679246854Sdes		}
680246854Sdes		return;
681238104Sdes	}
682238104Sdes}
683246854Sdes
684246854Sdesstatic void
685246854Sdesudav_intr_callback(struct usb_xfer *xfer, usb_error_t error)
686246854Sdes{
687246854Sdes	switch (USB_GET_STATE(xfer)) {
688246854Sdes	case USB_ST_TRANSFERRED:
689246854Sdes	case USB_ST_SETUP:
690246854Sdestr_setup:
691246854Sdes		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
692246854Sdes		usbd_transfer_submit(xfer);
693246854Sdes		return;
694246854Sdes
695246854Sdes	default:			/* Error */
696246854Sdes		if (error != USB_ERR_CANCELLED) {
697246854Sdes			/* try to clear stall first */
698238104Sdes			usbd_xfer_set_stall(xfer);
699246854Sdes			goto tr_setup;
700246854Sdes		}
701246854Sdes		return;
702246854Sdes	}
703246854Sdes}
704246854Sdes
705246854Sdesstatic void
706246854Sdesudav_stop(struct usb_ether *ue)
707246854Sdes{
708246854Sdes	struct udav_softc *sc = ue->ue_sc;
709246854Sdes	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
710246854Sdes
711246854Sdes	UDAV_LOCK_ASSERT(sc, MA_OWNED);
712246854Sdes
713246854Sdes	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
714246854Sdes	sc->sc_flags &= ~UDAV_FLAG_LINK;
715246854Sdes
716246854Sdes	/*
717246854Sdes	 * stop all the transfers, if not already stopped:
718238104Sdes	 */
719238104Sdes	usbd_transfer_stop(sc->sc_xfer[UDAV_BULK_DT_WR]);
720246854Sdes	usbd_transfer_stop(sc->sc_xfer[UDAV_BULK_DT_RD]);
721246854Sdes	usbd_transfer_stop(sc->sc_xfer[UDAV_INTR_DT_RD]);
722246854Sdes
723238104Sdes	udav_reset(sc);
724238104Sdes}
725246854Sdes
726246854Sdesstatic int
727246854Sdesudav_ifmedia_upd(struct ifnet *ifp)
728246854Sdes{
729246854Sdes	struct udav_softc *sc = ifp->if_softc;
730246854Sdes	struct mii_data *mii = GET_MII(sc);
731246854Sdes
732246854Sdes	UDAV_LOCK_ASSERT(sc, MA_OWNED);
733246854Sdes
734238104Sdes        sc->sc_flags &= ~UDAV_FLAG_LINK;
735238104Sdes	if (mii->mii_instance) {
736246854Sdes		struct mii_softc *miisc;
737246854Sdes
738246854Sdes		LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
739246854Sdes			mii_phy_reset(miisc);
740246854Sdes	}
741246854Sdes	mii_mediachg(mii);
742238104Sdes	return (0);
743238104Sdes}
744246854Sdes
745246854Sdesstatic void
746246854Sdesudav_ifmedia_status(struct ifnet *ifp, struct ifmediareq *ifmr)
747246854Sdes{
748246854Sdes	struct udav_softc *sc = ifp->if_softc;
749246854Sdes	struct mii_data *mii = GET_MII(sc);
750238104Sdes
751238104Sdes	UDAV_LOCK(sc);
752246854Sdes	mii_pollstat(mii);
753246854Sdes	UDAV_UNLOCK(sc);
754246854Sdes	ifmr->ifm_active = mii->mii_media_active;
755238104Sdes	ifmr->ifm_status = mii->mii_media_status;
756238104Sdes}
757246854Sdes
758246854Sdesstatic void
759246854Sdesudav_tick(struct usb_ether *ue)
760246854Sdes{
761246854Sdes	struct udav_softc *sc = ue->ue_sc;
762246854Sdes	struct mii_data *mii = GET_MII(sc);
763246854Sdes
764246854Sdes	UDAV_LOCK_ASSERT(sc, MA_OWNED);
765246854Sdes
766238104Sdes	mii_tick(mii);
767238104Sdes	if ((sc->sc_flags & UDAV_FLAG_LINK) == 0
768246854Sdes	    && mii->mii_media_status & IFM_ACTIVE &&
769246854Sdes	    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
770246854Sdes		sc->sc_flags |= UDAV_FLAG_LINK;
771238104Sdes		udav_start(ue);
772238104Sdes	}
773246854Sdes}
774246854Sdes
775246854Sdesstatic int
776246854Sdesudav_miibus_readreg(device_t dev, int phy, int reg)
777246854Sdes{
778246854Sdes	struct udav_softc *sc = device_get_softc(dev);
779246854Sdes	uint16_t data16;
780246854Sdes	uint8_t val[2];
781246854Sdes	int locked;
782238104Sdes
783238104Sdes	/* XXX: one PHY only for the internal PHY */
784246854Sdes	if (phy != 0)
785246854Sdes		return (0);
786246854Sdes
787246854Sdes	locked = mtx_owned(&sc->sc_mtx);
788246854Sdes	if (!locked)
789246854Sdes		UDAV_LOCK(sc);
790238104Sdes
791238104Sdes	/* select internal PHY and set PHY register address */
792246854Sdes	udav_csr_write1(sc, UDAV_EPAR,
793246854Sdes	    UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK));
794246854Sdes
795246854Sdes	/* select PHY operation and start read command */
796246854Sdes	udav_csr_write1(sc, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRR);
797246854Sdes
798238104Sdes	/* XXX: should we wait? */
799238104Sdes
800246854Sdes	/* end read command */
801246854Sdes	UDAV_CLRBIT(sc, UDAV_EPCR, UDAV_EPCR_ERPRR);
802246854Sdes
803238104Sdes	/* retrieve the result from data registers */
804238104Sdes	udav_csr_read(sc, UDAV_EPDRL, val, 2);
805246854Sdes
806246854Sdes	data16 = (val[0] | (val[1] << 8));
807246854Sdes
808246854Sdes	DPRINTFN(11, "phy=%d reg=0x%04x => 0x%04x\n",
809246854Sdes	    phy, reg, data16);
810246854Sdes
811238104Sdes	if (!locked)
812238104Sdes		UDAV_UNLOCK(sc);
813246854Sdes	return (data16);
814246854Sdes}
815246854Sdes
816246854Sdesstatic int
817246854Sdesudav_miibus_writereg(device_t dev, int phy, int reg, int data)
818246854Sdes{
819238104Sdes	struct udav_softc *sc = device_get_softc(dev);
820238104Sdes	uint8_t val[2];
821246854Sdes	int locked;
822246854Sdes
823246854Sdes	/* XXX: one PHY only for the internal PHY */
824246854Sdes	if (phy != 0)
825246854Sdes		return (0);
826246854Sdes
827246854Sdes	locked = mtx_owned(&sc->sc_mtx);
828246854Sdes	if (!locked)
829246854Sdes		UDAV_LOCK(sc);
830238104Sdes
831238104Sdes	/* select internal PHY and set PHY register address */
832246854Sdes	udav_csr_write1(sc, UDAV_EPAR,
833246854Sdes	    UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK));
834246854Sdes
835246854Sdes	/* put the value to the data registers */
836246854Sdes	val[0] = (data & 0xff);
837246854Sdes	val[1] = (data >> 8) & 0xff;
838238104Sdes	udav_csr_write(sc, UDAV_EPDRL, val, 2);
839238104Sdes
840246854Sdes	/* select PHY operation and start write command */
841246854Sdes	udav_csr_write1(sc, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRW);
842246854Sdes
843238104Sdes	/* XXX: should we wait? */
844238104Sdes
845246854Sdes	/* end write command */
846246854Sdes	UDAV_CLRBIT(sc, UDAV_EPCR, UDAV_EPCR_ERPRW);
847246854Sdes
848246854Sdes	if (!locked)
849246854Sdes		UDAV_UNLOCK(sc);
850246854Sdes	return (0);
851238104Sdes}
852238104Sdes
853246854Sdesstatic void
854246854Sdesudav_miibus_statchg(device_t dev)
855246854Sdes{
856246854Sdes	/* nothing to do */
857246854Sdes}
858246854Sdes