if_udav.c revision 188746
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/usb2/ethernet/if_udav2.c 188746 2009-02-18 06:33:10Z 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/usb2/ethernet/if_udav2.c 188746 2009-02-18 06:33:10Z thompsa $");
48184610Salfred
49188746Sthompsa#include "usbdevs.h"
50184610Salfred#include <dev/usb2/include/usb2_standard.h>
51184610Salfred#include <dev/usb2/include/usb2_mfunc.h>
52184610Salfred#include <dev/usb2/include/usb2_error.h>
53184610Salfred
54184610Salfred#define	USB_DEBUG_VAR udav_debug
55184610Salfred
56184610Salfred#include <dev/usb2/core/usb2_core.h>
57184610Salfred#include <dev/usb2/core/usb2_lookup.h>
58184610Salfred#include <dev/usb2/core/usb2_process.h>
59184610Salfred#include <dev/usb2/core/usb2_debug.h>
60184610Salfred#include <dev/usb2/core/usb2_request.h>
61184610Salfred#include <dev/usb2/core/usb2_busdma.h>
62184610Salfred#include <dev/usb2/core/usb2_util.h>
63184610Salfred
64184610Salfred#include <dev/usb2/ethernet/usb2_ethernet.h>
65187192Sthompsa#include <dev/usb2/ethernet/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;
72184610Salfredstatic device_shutdown_t udav_shutdown;
73184610Salfred
74184610Salfredstatic usb2_callback_t udav_bulk_write_callback;
75184610Salfredstatic usb2_callback_t udav_bulk_read_callback;
76184610Salfredstatic usb2_callback_t udav_intr_callback;
77184610Salfred
78188412Sthompsastatic usb2_ether_fn_t udav_attach_post;
79188412Sthompsastatic usb2_ether_fn_t udav_init;
80188412Sthompsastatic usb2_ether_fn_t udav_stop;
81188412Sthompsastatic usb2_ether_fn_t udav_start;
82188412Sthompsastatic usb2_ether_fn_t udav_tick;
83188412Sthompsastatic usb2_ether_fn_t udav_setmulti;
84188412Sthompsastatic usb2_ether_fn_t udav_setpromisc;
85184610Salfred
86188412Sthompsastatic int	udav_csr_read(struct udav_softc *, uint16_t, void *, int);
87188412Sthompsastatic int	udav_csr_write(struct udav_softc *, uint16_t, void *, int);
88188412Sthompsastatic uint8_t	udav_csr_read1(struct udav_softc *, uint16_t);
89188412Sthompsastatic int	udav_csr_write1(struct udav_softc *, uint16_t, uint8_t);
90188412Sthompsastatic void	udav_reset(struct udav_softc *);
91188412Sthompsastatic int	udav_ifmedia_upd(struct ifnet *);
92188412Sthompsastatic void	udav_ifmedia_status(struct ifnet *, struct ifmediareq *);
93184610Salfred
94188412Sthompsastatic miibus_readreg_t udav_miibus_readreg;
95188412Sthompsastatic miibus_writereg_t udav_miibus_writereg;
96188412Sthompsastatic miibus_statchg_t udav_miibus_statchg;
97184610Salfred
98187259Sthompsastatic const struct usb2_config udav_config[UDAV_N_TRANSFER] = {
99184610Salfred
100187259Sthompsa	[UDAV_BULK_DT_WR] = {
101184610Salfred		.type = UE_BULK,
102184610Salfred		.endpoint = UE_ADDR_ANY,
103184610Salfred		.direction = UE_DIR_OUT,
104184610Salfred		.mh.bufsize = (MCLBYTES + 2),
105184610Salfred		.mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
106188412Sthompsa		.mh.callback = udav_bulk_write_callback,
107184610Salfred		.mh.timeout = 10000,	/* 10 seconds */
108184610Salfred	},
109184610Salfred
110187259Sthompsa	[UDAV_BULK_DT_RD] = {
111184610Salfred		.type = UE_BULK,
112184610Salfred		.endpoint = UE_ADDR_ANY,
113184610Salfred		.direction = UE_DIR_IN,
114184610Salfred		.mh.bufsize = (MCLBYTES + 3),
115184610Salfred		.mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
116188412Sthompsa		.mh.callback = udav_bulk_read_callback,
117184610Salfred		.mh.timeout = 0,	/* no timeout */
118184610Salfred	},
119184610Salfred
120187259Sthompsa	[UDAV_INTR_DT_RD] = {
121184610Salfred		.type = UE_INTERRUPT,
122184610Salfred		.endpoint = UE_ADDR_ANY,
123184610Salfred		.direction = UE_DIR_IN,
124184610Salfred		.mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
125184610Salfred		.mh.bufsize = 0,	/* use wMaxPacketSize */
126188412Sthompsa		.mh.callback = udav_intr_callback,
127184610Salfred	},
128184610Salfred};
129184610Salfred
130184610Salfredstatic device_method_t udav_methods[] = {
131184610Salfred	/* Device interface */
132184610Salfred	DEVMETHOD(device_probe, udav_probe),
133184610Salfred	DEVMETHOD(device_attach, udav_attach),
134184610Salfred	DEVMETHOD(device_detach, udav_detach),
135184610Salfred	DEVMETHOD(device_shutdown, udav_shutdown),
136184610Salfred
137184610Salfred	/* bus interface */
138184610Salfred	DEVMETHOD(bus_print_child, bus_generic_print_child),
139184610Salfred	DEVMETHOD(bus_driver_added, bus_generic_driver_added),
140184610Salfred
141184610Salfred	/* MII interface */
142188412Sthompsa	DEVMETHOD(miibus_readreg, udav_miibus_readreg),
143188412Sthompsa	DEVMETHOD(miibus_writereg, udav_miibus_writereg),
144188412Sthompsa	DEVMETHOD(miibus_statchg, udav_miibus_statchg),
145184610Salfred
146184610Salfred	{0, 0}
147184610Salfred};
148184610Salfred
149184610Salfredstatic driver_t udav_driver = {
150184610Salfred	.name = "udav",
151184610Salfred	.methods = udav_methods,
152184610Salfred	.size = sizeof(struct udav_softc),
153184610Salfred};
154184610Salfred
155184610Salfredstatic devclass_t udav_devclass;
156184610Salfred
157184610SalfredDRIVER_MODULE(udav, ushub, udav_driver, udav_devclass, NULL, 0);
158184610SalfredDRIVER_MODULE(miibus, udav, miibus_driver, miibus_devclass, 0, 0);
159184610SalfredMODULE_DEPEND(udav, usb2_ethernet, 1, 1, 1);
160184610SalfredMODULE_DEPEND(udav, usb2_core, 1, 1, 1);
161184610SalfredMODULE_DEPEND(udav, ether, 1, 1, 1);
162184610SalfredMODULE_DEPEND(udav, miibus, 1, 1, 1);
163184610Salfred
164188412Sthompsastatic const struct usb2_ether_methods udav_ue_methods = {
165188412Sthompsa	.ue_attach_post = udav_attach_post,
166188412Sthompsa	.ue_start = udav_start,
167188412Sthompsa	.ue_init = udav_init,
168188412Sthompsa	.ue_stop = udav_stop,
169188412Sthompsa	.ue_tick = udav_tick,
170188412Sthompsa	.ue_setmulti = udav_setmulti,
171188412Sthompsa	.ue_setpromisc = udav_setpromisc,
172188412Sthompsa	.ue_mii_upd = udav_ifmedia_upd,
173188412Sthompsa	.ue_mii_sts = udav_ifmedia_status,
174188412Sthompsa};
175188412Sthompsa
176184610Salfred#if USB_DEBUG
177184610Salfredstatic int udav_debug = 0;
178184610Salfred
179184610SalfredSYSCTL_NODE(_hw_usb2, OID_AUTO, udav, CTLFLAG_RW, 0, "USB udav");
180184610SalfredSYSCTL_INT(_hw_usb2_udav, OID_AUTO, debug, CTLFLAG_RW, &udav_debug, 0,
181184610Salfred    "Debug level");
182184610Salfred#endif
183184610Salfred
184188412Sthompsa#define	UDAV_SETBIT(sc, reg, x)	\
185188412Sthompsa	udav_csr_write1(sc, reg, udav_csr_read1(sc, reg) | (x))
186184610Salfred
187188412Sthompsa#define	UDAV_CLRBIT(sc, reg, x)	\
188188412Sthompsa	udav_csr_write1(sc, reg, udav_csr_read1(sc, reg) & ~(x))
189184610Salfred
190184610Salfredstatic const struct usb2_device_id udav_devs[] = {
191184610Salfred	/* ShanTou DM9601 USB NIC */
192184610Salfred	{USB_VPI(USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_DM9601, 0)},
193184610Salfred	/* ShanTou ST268 USB NIC */
194184610Salfred	{USB_VPI(USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_ST268, 0)},
195184610Salfred	/* Corega USB-TXC */
196184610Salfred	{USB_VPI(USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TXC, 0)},
197184610Salfred};
198184610Salfred
199188412Sthompsastatic void
200188412Sthompsaudav_attach_post(struct usb2_ether *ue)
201188412Sthompsa{
202188412Sthompsa	struct udav_softc *sc = usb2_ether_getsc(ue);
203188412Sthompsa
204188412Sthompsa	/* reset the adapter */
205188412Sthompsa	udav_reset(sc);
206188412Sthompsa
207188412Sthompsa	/* Get Ethernet Address */
208188412Sthompsa	udav_csr_read(sc, UDAV_PAR, ue->ue_eaddr, ETHER_ADDR_LEN);
209188412Sthompsa}
210188412Sthompsa
211184610Salfredstatic int
212184610Salfredudav_probe(device_t dev)
213184610Salfred{
214184610Salfred	struct usb2_attach_arg *uaa = device_get_ivars(dev);
215184610Salfred
216188412Sthompsa	if (uaa->usb2_mode != USB_MODE_HOST)
217184610Salfred		return (ENXIO);
218188412Sthompsa	if (uaa->info.bConfigIndex != UDAV_CONFIG_INDEX)
219184610Salfred		return (ENXIO);
220188412Sthompsa	if (uaa->info.bIfaceIndex != UDAV_IFACE_INDEX)
221184610Salfred		return (ENXIO);
222188412Sthompsa
223184610Salfred	return (usb2_lookup_id_by_uaa(udav_devs, sizeof(udav_devs), uaa));
224184610Salfred}
225184610Salfred
226184610Salfredstatic int
227184610Salfredudav_attach(device_t dev)
228184610Salfred{
229184610Salfred	struct usb2_attach_arg *uaa = device_get_ivars(dev);
230184610Salfred	struct udav_softc *sc = device_get_softc(dev);
231188412Sthompsa	struct usb2_ether *ue = &sc->sc_ue;
232184610Salfred	uint8_t iface_index;
233188412Sthompsa	int error;
234184610Salfred
235184610Salfred	sc->sc_flags = USB_GET_DRIVER_INFO(uaa);
236184610Salfred
237184610Salfred	device_set_usb2_desc(dev);
238184610Salfred
239188412Sthompsa	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
240184610Salfred
241184610Salfred	iface_index = UDAV_IFACE_INDEX;
242184610Salfred	error = usb2_transfer_setup(uaa->device, &iface_index,
243187259Sthompsa	    sc->sc_xfer, udav_config, UDAV_N_TRANSFER, sc, &sc->sc_mtx);
244184610Salfred	if (error) {
245188412Sthompsa		device_printf(dev, "allocating USB transfers failed!\n");
246184610Salfred		goto detach;
247184610Salfred	}
248188412Sthompsa
249188412Sthompsa	ue->ue_sc = sc;
250188412Sthompsa	ue->ue_dev = dev;
251188412Sthompsa	ue->ue_udev = uaa->device;
252188412Sthompsa	ue->ue_mtx = &sc->sc_mtx;
253188412Sthompsa	ue->ue_methods = &udav_ue_methods;
254188412Sthompsa
255188412Sthompsa	error = usb2_ether_ifattach(ue);
256184610Salfred	if (error) {
257188412Sthompsa		device_printf(dev, "could not attach interface\n");
258184610Salfred		goto detach;
259184610Salfred	}
260184610Salfred
261184610Salfred	return (0);			/* success */
262184610Salfred
263184610Salfreddetach:
264184610Salfred	udav_detach(dev);
265184610Salfred	return (ENXIO);			/* failure */
266184610Salfred}
267184610Salfred
268184610Salfredstatic int
269184610Salfredudav_detach(device_t dev)
270184610Salfred{
271184610Salfred	struct udav_softc *sc = device_get_softc(dev);
272188412Sthompsa	struct usb2_ether *ue = &sc->sc_ue;
273184610Salfred
274187259Sthompsa	usb2_transfer_unsetup(sc->sc_xfer, UDAV_N_TRANSFER);
275188412Sthompsa	usb2_ether_ifdetach(ue);
276184610Salfred	mtx_destroy(&sc->sc_mtx);
277184610Salfred
278184610Salfred	return (0);
279184610Salfred}
280184610Salfred
281184610Salfred#if 0
282188412Sthompsastatic int
283188412Sthompsaudav_mem_read(struct udav_softc *sc, uint16_t offset, void *buf,
284188412Sthompsa    int len)
285184610Salfred{
286184610Salfred	struct usb2_device_request req;
287184610Salfred
288184610Salfred	len &= 0xff;
289184610Salfred
290184610Salfred	req.bmRequestType = UT_READ_VENDOR_DEVICE;
291184610Salfred	req.bRequest = UDAV_REQ_MEM_READ;
292184610Salfred	USETW(req.wValue, 0x0000);
293184610Salfred	USETW(req.wIndex, offset);
294184610Salfred	USETW(req.wLength, len);
295184610Salfred
296188412Sthompsa	return (usb2_ether_do_request(&sc->sc_ue, &req, buf, 1000));
297184610Salfred}
298184610Salfred
299188412Sthompsastatic int
300188412Sthompsaudav_mem_write(struct udav_softc *sc, uint16_t offset, void *buf,
301188412Sthompsa    int len)
302184610Salfred{
303184610Salfred	struct usb2_device_request req;
304184610Salfred
305184610Salfred	len &= 0xff;
306184610Salfred
307184610Salfred	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
308184610Salfred	req.bRequest = UDAV_REQ_MEM_WRITE;
309184610Salfred	USETW(req.wValue, 0x0000);
310184610Salfred	USETW(req.wIndex, offset);
311184610Salfred	USETW(req.wLength, len);
312184610Salfred
313188412Sthompsa	return (usb2_ether_do_request(&sc->sc_ue, &req, buf, 1000));
314184610Salfred}
315184610Salfred
316188412Sthompsastatic int
317188412Sthompsaudav_mem_write1(struct udav_softc *sc, uint16_t offset,
318184610Salfred    uint8_t ch)
319184610Salfred{
320184610Salfred	struct usb2_device_request req;
321184610Salfred
322184610Salfred	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
323184610Salfred	req.bRequest = UDAV_REQ_MEM_WRITE1;
324184610Salfred	USETW(req.wValue, ch);
325184610Salfred	USETW(req.wIndex, offset);
326184610Salfred	USETW(req.wLength, 0x0000);
327184610Salfred
328188412Sthompsa	return (usb2_ether_do_request(&sc->sc_ue, &req, NULL, 1000));
329184610Salfred}
330184610Salfred#endif
331184610Salfred
332188412Sthompsastatic int
333188412Sthompsaudav_csr_read(struct udav_softc *sc, uint16_t offset, void *buf, int len)
334184610Salfred{
335184610Salfred	struct usb2_device_request req;
336184610Salfred
337184610Salfred	len &= 0xff;
338184610Salfred
339184610Salfred	req.bmRequestType = UT_READ_VENDOR_DEVICE;
340184610Salfred	req.bRequest = UDAV_REQ_REG_READ;
341184610Salfred	USETW(req.wValue, 0x0000);
342184610Salfred	USETW(req.wIndex, offset);
343184610Salfred	USETW(req.wLength, len);
344184610Salfred
345188412Sthompsa	return (usb2_ether_do_request(&sc->sc_ue, &req, buf, 1000));
346184610Salfred}
347184610Salfred
348188412Sthompsastatic int
349188412Sthompsaudav_csr_write(struct udav_softc *sc, uint16_t offset, void *buf, int len)
350184610Salfred{
351184610Salfred	struct usb2_device_request req;
352184610Salfred
353184610Salfred	offset &= 0xff;
354184610Salfred	len &= 0xff;
355184610Salfred
356184610Salfred	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
357184610Salfred	req.bRequest = UDAV_REQ_REG_WRITE;
358184610Salfred	USETW(req.wValue, 0x0000);
359184610Salfred	USETW(req.wIndex, offset);
360184610Salfred	USETW(req.wLength, len);
361184610Salfred
362188412Sthompsa	return (usb2_ether_do_request(&sc->sc_ue, &req, buf, 1000));
363184610Salfred}
364184610Salfred
365184610Salfredstatic uint8_t
366188412Sthompsaudav_csr_read1(struct udav_softc *sc, uint16_t offset)
367184610Salfred{
368184610Salfred	uint8_t val;
369184610Salfred
370188412Sthompsa	udav_csr_read(sc, offset, &val, 1);
371184610Salfred	return (val);
372184610Salfred}
373184610Salfred
374188412Sthompsastatic int
375188412Sthompsaudav_csr_write1(struct udav_softc *sc, uint16_t offset,
376184610Salfred    uint8_t ch)
377184610Salfred{
378184610Salfred	struct usb2_device_request req;
379184610Salfred
380184610Salfred	offset &= 0xff;
381184610Salfred
382184610Salfred	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
383184610Salfred	req.bRequest = UDAV_REQ_REG_WRITE1;
384184610Salfred	USETW(req.wValue, ch);
385184610Salfred	USETW(req.wIndex, offset);
386184610Salfred	USETW(req.wLength, 0x0000);
387184610Salfred
388188412Sthompsa	return (usb2_ether_do_request(&sc->sc_ue, &req, NULL, 1000));
389184610Salfred}
390184610Salfred
391184610Salfredstatic void
392188412Sthompsaudav_init(struct usb2_ether *ue)
393184610Salfred{
394188412Sthompsa	struct udav_softc *sc = ue->ue_sc;
395188412Sthompsa	struct ifnet *ifp = usb2_ether_getifp(&sc->sc_ue);
396184610Salfred
397188412Sthompsa	UDAV_LOCK_ASSERT(sc, MA_OWNED);
398184610Salfred
399184610Salfred	/*
400184610Salfred	 * Cancel pending I/O
401184610Salfred	 */
402188412Sthompsa	udav_stop(ue);
403184610Salfred
404184610Salfred	/* set MAC address */
405188412Sthompsa	udav_csr_write(sc, UDAV_PAR, IF_LLADDR(ifp), ETHER_ADDR_LEN);
406184610Salfred
407184610Salfred	/* initialize network control register */
408184610Salfred
409184610Salfred	/* disable loopback  */
410188412Sthompsa	UDAV_CLRBIT(sc, UDAV_NCR, UDAV_NCR_LBK0 | UDAV_NCR_LBK1);
411184610Salfred
412184610Salfred	/* Initialize RX control register */
413188412Sthompsa	UDAV_SETBIT(sc, UDAV_RCR, UDAV_RCR_DIS_LONG | UDAV_RCR_DIS_CRC);
414184610Salfred
415184610Salfred	/* load multicast filter and update promiscious mode bit */
416188412Sthompsa	udav_setpromisc(ue);
417184610Salfred
418184610Salfred	/* enable RX */
419188412Sthompsa	UDAV_SETBIT(sc, UDAV_RCR, UDAV_RCR_RXEN);
420184610Salfred
421184610Salfred	/* clear POWER_DOWN state of internal PHY */
422188412Sthompsa	UDAV_SETBIT(sc, UDAV_GPCR, UDAV_GPCR_GEP_CNTL0);
423188412Sthompsa	UDAV_CLRBIT(sc, UDAV_GPR, UDAV_GPR_GEPIO0);
424184610Salfred
425188412Sthompsa	usb2_transfer_set_stall(sc->sc_xfer[UDAV_BULK_DT_WR]);
426184610Salfred
427188412Sthompsa	ifp->if_drv_flags |= IFF_DRV_RUNNING;
428188412Sthompsa	udav_start(ue);
429184610Salfred}
430184610Salfred
431184610Salfredstatic void
432188412Sthompsaudav_reset(struct udav_softc *sc)
433184610Salfred{
434188412Sthompsa	int i;
435184610Salfred
436184610Salfred	/* Select PHY */
437184610Salfred#if 1
438184610Salfred	/*
439184610Salfred	 * XXX: force select internal phy.
440184610Salfred	 *	external phy routines are not tested.
441184610Salfred	 */
442188412Sthompsa	UDAV_CLRBIT(sc, UDAV_NCR, UDAV_NCR_EXT_PHY);
443184610Salfred#else
444188412Sthompsa	if (sc->sc_flags & UDAV_EXT_PHY)
445188412Sthompsa		UDAV_SETBIT(sc, UDAV_NCR, UDAV_NCR_EXT_PHY);
446188412Sthompsa	else
447188412Sthompsa		UDAV_CLRBIT(sc, UDAV_NCR, UDAV_NCR_EXT_PHY);
448184610Salfred#endif
449184610Salfred
450188412Sthompsa	UDAV_SETBIT(sc, UDAV_NCR, UDAV_NCR_RST);
451184610Salfred
452188412Sthompsa	for (i = 0; i < UDAV_TX_TIMEOUT; i++) {
453188412Sthompsa		if (!(udav_csr_read1(sc, UDAV_NCR) & UDAV_NCR_RST))
454184610Salfred			break;
455188412Sthompsa		if (usb2_ether_pause(&sc->sc_ue, hz / 100))
456188412Sthompsa			break;
457184610Salfred	}
458184610Salfred
459188412Sthompsa	usb2_ether_pause(&sc->sc_ue, hz / 100);
460184610Salfred}
461184610Salfred
462184610Salfred#define	UDAV_BITS	6
463184610Salfredstatic void
464188412Sthompsaudav_setmulti(struct usb2_ether *ue)
465184610Salfred{
466188412Sthompsa	struct udav_softc *sc = ue->ue_sc;
467188412Sthompsa	struct ifnet *ifp = usb2_ether_getifp(&sc->sc_ue);
468188412Sthompsa	struct ifmultiaddr *ifma;
469188412Sthompsa	uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
470188412Sthompsa	int h = 0;
471184610Salfred
472188412Sthompsa	UDAV_LOCK_ASSERT(sc, MA_OWNED);
473184610Salfred
474188412Sthompsa	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
475188412Sthompsa		UDAV_SETBIT(sc, UDAV_RCR, UDAV_RCR_ALL|UDAV_RCR_PRMSC);
476188412Sthompsa		return;
477188412Sthompsa	}
478188412Sthompsa
479188412Sthompsa	/* first, zot all the existing hash bits */
480188412Sthompsa	memset(hashtbl, 0x00, sizeof(hashtbl));
481188412Sthompsa	hashtbl[7] |= 0x80;	/* broadcast address */
482188412Sthompsa	udav_csr_write(sc, UDAV_MAR, hashtbl, sizeof(hashtbl));
483188412Sthompsa
484188412Sthompsa	/* now program new ones */
485188412Sthompsa	IF_ADDR_LOCK(ifp);
486188412Sthompsa	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
487188412Sthompsa	{
488188412Sthompsa		if (ifma->ifma_addr->sa_family != AF_LINK)
489188412Sthompsa			continue;
490188412Sthompsa		h = ether_crc32_be(LLADDR((struct sockaddr_dl *)
491188412Sthompsa		    ifma->ifma_addr), ETHER_ADDR_LEN) >> 26;
492188412Sthompsa		hashtbl[h / 8] |= 1 << (h % 8);
493188412Sthompsa	}
494188412Sthompsa	IF_ADDR_UNLOCK(ifp);
495188412Sthompsa
496188412Sthompsa	/* disable all multicast */
497188412Sthompsa	UDAV_CLRBIT(sc, UDAV_RCR, UDAV_RCR_ALL);
498188412Sthompsa
499188412Sthompsa	/* write hash value to the register */
500188412Sthompsa	udav_csr_write(sc, UDAV_MAR, hashtbl, sizeof(hashtbl));
501184610Salfred}
502184610Salfred
503184610Salfredstatic void
504188412Sthompsaudav_setpromisc(struct usb2_ether *ue)
505184610Salfred{
506188412Sthompsa	struct udav_softc *sc = ue->ue_sc;
507188412Sthompsa	struct ifnet *ifp = usb2_ether_getifp(&sc->sc_ue);
508184610Salfred	uint8_t rxmode;
509184610Salfred
510188412Sthompsa	rxmode = udav_csr_read1(sc, UDAV_RCR);
511184610Salfred	rxmode &= ~(UDAV_RCR_ALL | UDAV_RCR_PRMSC);
512184610Salfred
513188412Sthompsa	if (ifp->if_flags & IFF_PROMISC)
514184610Salfred		rxmode |= UDAV_RCR_ALL | UDAV_RCR_PRMSC;
515188412Sthompsa	else if (ifp->if_flags & IFF_ALLMULTI)
516184610Salfred		rxmode |= UDAV_RCR_ALL;
517184610Salfred
518184610Salfred	/* write new mode bits */
519188412Sthompsa	udav_csr_write1(sc, UDAV_RCR, rxmode);
520184610Salfred}
521184610Salfred
522184610Salfredstatic void
523188412Sthompsaudav_start(struct usb2_ether *ue)
524184610Salfred{
525188412Sthompsa	struct udav_softc *sc = ue->ue_sc;
526184610Salfred
527188412Sthompsa	/*
528188412Sthompsa	 * start the USB transfers, if not already started:
529188412Sthompsa	 */
530188412Sthompsa	usb2_transfer_start(sc->sc_xfer[UDAV_INTR_DT_RD]);
531188412Sthompsa	usb2_transfer_start(sc->sc_xfer[UDAV_BULK_DT_RD]);
532188412Sthompsa	usb2_transfer_start(sc->sc_xfer[UDAV_BULK_DT_WR]);
533184610Salfred}
534184610Salfred
535184610Salfredstatic void
536184610Salfredudav_bulk_write_callback(struct usb2_xfer *xfer)
537184610Salfred{
538184610Salfred	struct udav_softc *sc = xfer->priv_sc;
539188412Sthompsa	struct ifnet *ifp = usb2_ether_getifp(&sc->sc_ue);
540184610Salfred	struct mbuf *m;
541188412Sthompsa	int extra_len;
542188412Sthompsa	int temp_len;
543184610Salfred	uint8_t buf[2];
544184610Salfred
545184610Salfred	switch (USB_GET_STATE(xfer)) {
546184610Salfred	case USB_ST_TRANSFERRED:
547184610Salfred		DPRINTFN(11, "transfer complete\n");
548184610Salfred		ifp->if_opackets++;
549184610Salfred
550188412Sthompsa		/* FALLTHROUGH */
551184610Salfred	case USB_ST_SETUP:
552188412Sthompsatr_setup:
553188412Sthompsa		if ((sc->sc_flags & UDAV_FLAG_LINK) == 0) {
554184610Salfred			/*
555184610Salfred			 * don't send anything if there is no link !
556184610Salfred			 */
557188412Sthompsa			return;
558184610Salfred		}
559184610Salfred		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
560184610Salfred
561188412Sthompsa		if (m == NULL)
562188412Sthompsa			return;
563188412Sthompsa		if (m->m_pkthdr.len > MCLBYTES)
564184610Salfred			m->m_pkthdr.len = MCLBYTES;
565184610Salfred		if (m->m_pkthdr.len < UDAV_MIN_FRAME_LEN) {
566184610Salfred			extra_len = UDAV_MIN_FRAME_LEN - m->m_pkthdr.len;
567184610Salfred		} else {
568184610Salfred			extra_len = 0;
569184610Salfred		}
570184610Salfred
571184610Salfred		temp_len = (m->m_pkthdr.len + extra_len);
572184610Salfred
573184610Salfred		/*
574184610Salfred		 * the frame length is specified in the first 2 bytes of the
575184610Salfred		 * buffer
576184610Salfred		 */
577184610Salfred		buf[0] = (uint8_t)(temp_len);
578184610Salfred		buf[1] = (uint8_t)(temp_len >> 8);
579184610Salfred
580184610Salfred		temp_len += 2;
581184610Salfred
582184610Salfred		usb2_copy_in(xfer->frbuffers, 0, buf, 2);
583184610Salfred
584184610Salfred		usb2_m_copy_in(xfer->frbuffers, 2,
585184610Salfred		    m, 0, m->m_pkthdr.len);
586184610Salfred
587184610Salfred		if (extra_len) {
588184610Salfred			usb2_bzero(xfer->frbuffers, temp_len - extra_len,
589184610Salfred			    extra_len);
590184610Salfred		}
591184610Salfred		/*
592184610Salfred		 * if there's a BPF listener, bounce a copy
593184610Salfred		 * of this frame to him:
594184610Salfred		 */
595184610Salfred		BPF_MTAP(ifp, m);
596184610Salfred
597184610Salfred		m_freem(m);
598184610Salfred
599184610Salfred		xfer->frlengths[0] = temp_len;
600184610Salfred		usb2_start_hardware(xfer);
601184610Salfred		return;
602184610Salfred
603184610Salfred	default:			/* Error */
604184610Salfred		DPRINTFN(11, "transfer error, %s\n",
605184610Salfred		    usb2_errstr(xfer->error));
606184610Salfred
607188412Sthompsa		ifp->if_oerrors++;
608188412Sthompsa
609184610Salfred		if (xfer->error != USB_ERR_CANCELLED) {
610184610Salfred			/* try to clear stall first */
611188412Sthompsa			xfer->flags.stall_pipe = 1;
612188412Sthompsa			goto tr_setup;
613184610Salfred		}
614184610Salfred		return;
615184610Salfred	}
616184610Salfred}
617184610Salfred
618184610Salfredstatic void
619184610Salfredudav_bulk_read_callback(struct usb2_xfer *xfer)
620184610Salfred{
621184610Salfred	struct udav_softc *sc = xfer->priv_sc;
622188412Sthompsa	struct usb2_ether *ue = &sc->sc_ue;
623188412Sthompsa	struct ifnet *ifp = usb2_ether_getifp(ue);
624188412Sthompsa	struct udav_rxpkt stat;
625188412Sthompsa	int len;
626184610Salfred
627184610Salfred	switch (USB_GET_STATE(xfer)) {
628184610Salfred	case USB_ST_TRANSFERRED:
629184610Salfred
630188412Sthompsa		if (xfer->actlen < sizeof(stat) + ETHER_CRC_LEN) {
631184610Salfred			ifp->if_ierrors++;
632184610Salfred			goto tr_setup;
633184610Salfred		}
634188412Sthompsa		usb2_copy_out(xfer->frbuffers, 0, &stat, sizeof(stat));
635188412Sthompsa		xfer->actlen -= sizeof(stat);
636188412Sthompsa		len = min(xfer->actlen, le16toh(stat.pktlen));
637188412Sthompsa		len -= ETHER_CRC_LEN;
638184610Salfred
639188412Sthompsa		if (stat.rxstat & UDAV_RSR_LCS) {
640184610Salfred			ifp->if_collisions++;
641184610Salfred			goto tr_setup;
642184610Salfred		}
643188412Sthompsa		if (stat.rxstat & UDAV_RSR_ERR) {
644184610Salfred			ifp->if_ierrors++;
645184610Salfred			goto tr_setup;
646184610Salfred		}
647188412Sthompsa		usb2_ether_rxbuf(ue, xfer->frbuffers, sizeof(stat), len);
648188412Sthompsa		/* FALLTHROUGH */
649184610Salfred	case USB_ST_SETUP:
650184610Salfredtr_setup:
651188412Sthompsa		xfer->frlengths[0] = xfer->max_data_length;
652188412Sthompsa		usb2_start_hardware(xfer);
653188412Sthompsa		usb2_ether_rxflush(ue);
654184610Salfred		return;
655184610Salfred
656184610Salfred	default:			/* Error */
657188412Sthompsa		DPRINTF("bulk read error, %s\n",
658188412Sthompsa		    usb2_errstr(xfer->error));
659188412Sthompsa
660184610Salfred		if (xfer->error != USB_ERR_CANCELLED) {
661184610Salfred			/* try to clear stall first */
662188412Sthompsa			xfer->flags.stall_pipe = 1;
663188412Sthompsa			goto tr_setup;
664184610Salfred		}
665184610Salfred		return;
666184610Salfred	}
667184610Salfred}
668184610Salfred
669184610Salfredstatic void
670184610Salfredudav_intr_callback(struct usb2_xfer *xfer)
671184610Salfred{
672184610Salfred	switch (USB_GET_STATE(xfer)) {
673184610Salfred	case USB_ST_TRANSFERRED:
674184610Salfred	case USB_ST_SETUP:
675188412Sthompsatr_setup:
676188412Sthompsa		xfer->frlengths[0] = xfer->max_data_length;
677188412Sthompsa		usb2_start_hardware(xfer);
678184610Salfred		return;
679184610Salfred
680184610Salfred	default:			/* Error */
681184610Salfred		if (xfer->error != USB_ERR_CANCELLED) {
682188412Sthompsa			/* try to clear stall first */
683188412Sthompsa			xfer->flags.stall_pipe = 1;
684188412Sthompsa			goto tr_setup;
685184610Salfred		}
686184610Salfred		return;
687184610Salfred	}
688184610Salfred}
689184610Salfred
690184610Salfredstatic void
691188412Sthompsaudav_stop(struct usb2_ether *ue)
692184610Salfred{
693188412Sthompsa	struct udav_softc *sc = ue->ue_sc;
694188412Sthompsa	struct ifnet *ifp = usb2_ether_getifp(&sc->sc_ue);
695184610Salfred
696188412Sthompsa	UDAV_LOCK_ASSERT(sc, MA_OWNED);
697184610Salfred
698188412Sthompsa	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
699188412Sthompsa	sc->sc_flags &= ~UDAV_FLAG_LINK;
700184610Salfred
701184610Salfred	/*
702184610Salfred	 * stop all the transfers, if not already stopped:
703184610Salfred	 */
704187259Sthompsa	usb2_transfer_stop(sc->sc_xfer[UDAV_BULK_DT_WR]);
705187259Sthompsa	usb2_transfer_stop(sc->sc_xfer[UDAV_BULK_DT_RD]);
706187259Sthompsa	usb2_transfer_stop(sc->sc_xfer[UDAV_INTR_DT_RD]);
707184610Salfred
708188412Sthompsa	udav_reset(sc);
709184610Salfred}
710184610Salfred
711184610Salfredstatic int
712188412Sthompsaudav_ifmedia_upd(struct ifnet *ifp)
713184610Salfred{
714184610Salfred	struct udav_softc *sc = ifp->if_softc;
715184610Salfred	struct mii_data *mii = GET_MII(sc);
716184610Salfred
717188412Sthompsa	UDAV_LOCK_ASSERT(sc, MA_OWNED);
718184610Salfred
719188412Sthompsa        sc->sc_flags &= ~UDAV_FLAG_LINK;
720184610Salfred	if (mii->mii_instance) {
721184610Salfred		struct mii_softc *miisc;
722184610Salfred
723188412Sthompsa		LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
724184610Salfred			mii_phy_reset(miisc);
725184610Salfred	}
726184610Salfred	mii_mediachg(mii);
727188412Sthompsa	return (0);
728184610Salfred}
729184610Salfred
730184610Salfredstatic void
731188412Sthompsaudav_ifmedia_status(struct ifnet *ifp, struct ifmediareq *ifmr)
732184610Salfred{
733184610Salfred	struct udav_softc *sc = ifp->if_softc;
734188412Sthompsa	struct mii_data *mii = GET_MII(sc);
735184610Salfred
736188412Sthompsa	UDAV_LOCK(sc);
737188412Sthompsa	mii_pollstat(mii);
738188412Sthompsa	UDAV_UNLOCK(sc);
739188412Sthompsa	ifmr->ifm_active = mii->mii_media_active;
740188412Sthompsa	ifmr->ifm_status = mii->mii_media_status;
741184610Salfred}
742184610Salfred
743184610Salfredstatic void
744188412Sthompsaudav_tick(struct usb2_ether *ue)
745184610Salfred{
746188412Sthompsa	struct udav_softc *sc = ue->ue_sc;
747184610Salfred	struct mii_data *mii = GET_MII(sc);
748184610Salfred
749188412Sthompsa	UDAV_LOCK_ASSERT(sc, MA_OWNED);
750188412Sthompsa
751184610Salfred	mii_tick(mii);
752188412Sthompsa	if ((sc->sc_flags & UDAV_FLAG_LINK) == 0
753188412Sthompsa	    && mii->mii_media_status & IFM_ACTIVE &&
754188412Sthompsa	    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
755188412Sthompsa		sc->sc_flags |= UDAV_FLAG_LINK;
756188412Sthompsa		udav_start(ue);
757184610Salfred	}
758184610Salfred}
759184610Salfred
760184610Salfredstatic int
761188412Sthompsaudav_miibus_readreg(device_t dev, int phy, int reg)
762184610Salfred{
763184610Salfred	struct udav_softc *sc = device_get_softc(dev);
764184610Salfred	uint16_t data16;
765184610Salfred	uint8_t val[2];
766188412Sthompsa	int locked;
767184610Salfred
768184610Salfred	/* XXX: one PHY only for the internal PHY */
769188412Sthompsa	if (phy != 0)
770184610Salfred		return (0);
771184610Salfred
772188412Sthompsa	locked = mtx_owned(&sc->sc_mtx);
773188412Sthompsa	if (!locked)
774188412Sthompsa		UDAV_LOCK(sc);
775188412Sthompsa
776184610Salfred	/* select internal PHY and set PHY register address */
777188412Sthompsa	udav_csr_write1(sc, UDAV_EPAR,
778184610Salfred	    UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK));
779184610Salfred
780184610Salfred	/* select PHY operation and start read command */
781188412Sthompsa	udav_csr_write1(sc, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRR);
782184610Salfred
783184610Salfred	/* XXX: should we wait? */
784184610Salfred
785184610Salfred	/* end read command */
786188412Sthompsa	UDAV_CLRBIT(sc, UDAV_EPCR, UDAV_EPCR_ERPRR);
787184610Salfred
788184610Salfred	/* retrieve the result from data registers */
789188412Sthompsa	udav_csr_read(sc, UDAV_EPDRL, val, 2);
790184610Salfred
791184610Salfred	data16 = (val[0] | (val[1] << 8));
792184610Salfred
793184610Salfred	DPRINTFN(11, "phy=%d reg=0x%04x => 0x%04x\n",
794184610Salfred	    phy, reg, data16);
795184610Salfred
796188412Sthompsa	if (!locked)
797188412Sthompsa		UDAV_UNLOCK(sc);
798184610Salfred	return (data16);
799184610Salfred}
800184610Salfred
801184610Salfredstatic int
802188412Sthompsaudav_miibus_writereg(device_t dev, int phy, int reg, int data)
803184610Salfred{
804184610Salfred	struct udav_softc *sc = device_get_softc(dev);
805184610Salfred	uint8_t val[2];
806188412Sthompsa	int locked;
807184610Salfred
808184610Salfred	/* XXX: one PHY only for the internal PHY */
809188412Sthompsa	if (phy != 0)
810184610Salfred		return (0);
811184610Salfred
812188412Sthompsa	locked = mtx_owned(&sc->sc_mtx);
813188412Sthompsa	if (!locked)
814188412Sthompsa		UDAV_LOCK(sc);
815188412Sthompsa
816184610Salfred	/* select internal PHY and set PHY register address */
817188412Sthompsa	udav_csr_write1(sc, UDAV_EPAR,
818184610Salfred	    UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK));
819184610Salfred
820184610Salfred	/* put the value to the data registers */
821184610Salfred	val[0] = (data & 0xff);
822184610Salfred	val[1] = (data >> 8) & 0xff;
823188412Sthompsa	udav_csr_write(sc, UDAV_EPDRL, val, 2);
824184610Salfred
825184610Salfred	/* select PHY operation and start write command */
826188412Sthompsa	udav_csr_write1(sc, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRW);
827184610Salfred
828184610Salfred	/* XXX: should we wait? */
829184610Salfred
830184610Salfred	/* end write command */
831188412Sthompsa	UDAV_CLRBIT(sc, UDAV_EPCR, UDAV_EPCR_ERPRW);
832184610Salfred
833188412Sthompsa	if (!locked)
834188412Sthompsa		UDAV_UNLOCK(sc);
835184610Salfred	return (0);
836184610Salfred}
837184610Salfred
838184610Salfredstatic void
839188412Sthompsaudav_miibus_statchg(device_t dev)
840184610Salfred{
841184610Salfred	/* nothing to do */
842184610Salfred}
843184610Salfred
844184610Salfred/*
845184610Salfred * Stop all chip I/O so that the kernel's probe routines don't
846184610Salfred * get confused by errant DMAs when rebooting.
847184610Salfred */
848184610Salfredstatic int
849184610Salfredudav_shutdown(device_t dev)
850184610Salfred{
851184610Salfred	struct udav_softc *sc = device_get_softc(dev);
852184610Salfred
853188412Sthompsa	usb2_ether_ifshutdown(&sc->sc_ue);
854184610Salfred
855184610Salfred	return (0);
856184610Salfred}
857