if_udav.c revision 223486
1184610Salfred/*	$NetBSD: if_udav.c,v 1.2 2003/09/04 15:17:38 tsutsui Exp $	*/
2184610Salfred/*	$nabe: if_udav.c,v 1.3 2003/08/21 16:57:19 nabe Exp $	*/
3184610Salfred/*	$FreeBSD: head/sys/dev/usb/net/if_udav.c 223486 2011-06-24 02:30:02Z hselasky $	*/
4184610Salfred/*-
5184610Salfred * Copyright (c) 2003
6184610Salfred *     Shingo WATANABE <nabe@nabechan.org>.  All rights reserved.
7184610Salfred *
8184610Salfred * Redistribution and use in source and binary forms, with or without
9184610Salfred * modification, are permitted provided that the following conditions
10184610Salfred * are met:
11184610Salfred * 1. Redistributions of source code must retain the above copyright
12184610Salfred *    notice, this list of conditions and the following disclaimer.
13184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
14184610Salfred *    notice, this list of conditions and the following disclaimer in the
15184610Salfred *    documentation and/or other materials provided with the distribution.
16184610Salfred * 3. Neither the name of the author nor the names of any co-contributors
17184610Salfred *    may be used to endorse or promote products derived from this software
18184610Salfred *    without specific prior written permission.
19184610Salfred *
20184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23184610Salfred * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30184610Salfred * SUCH DAMAGE.
31184610Salfred *
32184610Salfred */
33184610Salfred
34184610Salfred/*
35184610Salfred * DM9601(DAVICOM USB to Ethernet MAC Controller with Integrated 10/100 PHY)
36184610Salfred * The spec can be found at the following url.
37184610Salfred *   http://www.davicom.com.tw/big5/download/Data%20Sheet/DM9601-DS-P01-930914.pdf
38184610Salfred */
39184610Salfred
40184610Salfred/*
41184610Salfred * TODO:
42184610Salfred *	Interrupt Endpoint support
43184610Salfred *	External PHYs
44184610Salfred */
45184610Salfred
46184610Salfred#include <sys/cdefs.h>
47184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb/net/if_udav.c 223486 2011-06-24 02:30:02Z hselasky $");
48184610Salfred
49194677Sthompsa#include <sys/stdint.h>
50194677Sthompsa#include <sys/stddef.h>
51194677Sthompsa#include <sys/param.h>
52194677Sthompsa#include <sys/queue.h>
53194677Sthompsa#include <sys/types.h>
54194677Sthompsa#include <sys/systm.h>
55194677Sthompsa#include <sys/kernel.h>
56194677Sthompsa#include <sys/bus.h>
57194677Sthompsa#include <sys/module.h>
58194677Sthompsa#include <sys/lock.h>
59194677Sthompsa#include <sys/mutex.h>
60194677Sthompsa#include <sys/condvar.h>
61194677Sthompsa#include <sys/sysctl.h>
62194677Sthompsa#include <sys/sx.h>
63194677Sthompsa#include <sys/unistd.h>
64194677Sthompsa#include <sys/callout.h>
65194677Sthompsa#include <sys/malloc.h>
66194677Sthompsa#include <sys/priv.h>
67194677Sthompsa
68194677Sthompsa#include <dev/usb/usb.h>
69194677Sthompsa#include <dev/usb/usbdi.h>
70194677Sthompsa#include <dev/usb/usbdi_util.h>
71188746Sthompsa#include "usbdevs.h"
72184610Salfred
73184610Salfred#define	USB_DEBUG_VAR udav_debug
74194677Sthompsa#include <dev/usb/usb_debug.h>
75188942Sthompsa#include <dev/usb/usb_process.h>
76184610Salfred
77188942Sthompsa#include <dev/usb/net/usb_ethernet.h>
78188942Sthompsa#include <dev/usb/net/if_udavreg.h>
79184610Salfred
80184610Salfred/* prototypes */
81184610Salfred
82184610Salfredstatic device_probe_t udav_probe;
83184610Salfredstatic device_attach_t udav_attach;
84184610Salfredstatic device_detach_t udav_detach;
85184610Salfred
86193045Sthompsastatic usb_callback_t udav_bulk_write_callback;
87193045Sthompsastatic usb_callback_t udav_bulk_read_callback;
88193045Sthompsastatic usb_callback_t udav_intr_callback;
89184610Salfred
90193045Sthompsastatic uether_fn_t udav_attach_post;
91193045Sthompsastatic uether_fn_t udav_init;
92193045Sthompsastatic uether_fn_t udav_stop;
93193045Sthompsastatic uether_fn_t udav_start;
94193045Sthompsastatic uether_fn_t udav_tick;
95193045Sthompsastatic uether_fn_t udav_setmulti;
96193045Sthompsastatic uether_fn_t udav_setpromisc;
97184610Salfred
98188412Sthompsastatic int	udav_csr_read(struct udav_softc *, uint16_t, void *, int);
99188412Sthompsastatic int	udav_csr_write(struct udav_softc *, uint16_t, void *, int);
100188412Sthompsastatic uint8_t	udav_csr_read1(struct udav_softc *, uint16_t);
101188412Sthompsastatic int	udav_csr_write1(struct udav_softc *, uint16_t, uint8_t);
102188412Sthompsastatic void	udav_reset(struct udav_softc *);
103188412Sthompsastatic int	udav_ifmedia_upd(struct ifnet *);
104188412Sthompsastatic void	udav_ifmedia_status(struct ifnet *, struct ifmediareq *);
105184610Salfred
106188412Sthompsastatic miibus_readreg_t udav_miibus_readreg;
107188412Sthompsastatic miibus_writereg_t udav_miibus_writereg;
108188412Sthompsastatic miibus_statchg_t udav_miibus_statchg;
109184610Salfred
110192984Sthompsastatic const struct usb_config udav_config[UDAV_N_TRANSFER] = {
111184610Salfred
112187259Sthompsa	[UDAV_BULK_DT_WR] = {
113184610Salfred		.type = UE_BULK,
114184610Salfred		.endpoint = UE_ADDR_ANY,
115184610Salfred		.direction = UE_DIR_OUT,
116190734Sthompsa		.bufsize = (MCLBYTES + 2),
117190734Sthompsa		.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
118190734Sthompsa		.callback = udav_bulk_write_callback,
119190734Sthompsa		.timeout = 10000,	/* 10 seconds */
120184610Salfred	},
121184610Salfred
122187259Sthompsa	[UDAV_BULK_DT_RD] = {
123184610Salfred		.type = UE_BULK,
124184610Salfred		.endpoint = UE_ADDR_ANY,
125184610Salfred		.direction = UE_DIR_IN,
126190734Sthompsa		.bufsize = (MCLBYTES + 3),
127190734Sthompsa		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
128190734Sthompsa		.callback = udav_bulk_read_callback,
129190734Sthompsa		.timeout = 0,	/* no timeout */
130184610Salfred	},
131184610Salfred
132187259Sthompsa	[UDAV_INTR_DT_RD] = {
133184610Salfred		.type = UE_INTERRUPT,
134184610Salfred		.endpoint = UE_ADDR_ANY,
135184610Salfred		.direction = UE_DIR_IN,
136190734Sthompsa		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
137190734Sthompsa		.bufsize = 0,	/* use wMaxPacketSize */
138190734Sthompsa		.callback = udav_intr_callback,
139184610Salfred	},
140184610Salfred};
141184610Salfred
142184610Salfredstatic device_method_t udav_methods[] = {
143184610Salfred	/* Device interface */
144184610Salfred	DEVMETHOD(device_probe, udav_probe),
145184610Salfred	DEVMETHOD(device_attach, udav_attach),
146184610Salfred	DEVMETHOD(device_detach, udav_detach),
147184610Salfred
148184610Salfred	/* bus interface */
149184610Salfred	DEVMETHOD(bus_print_child, bus_generic_print_child),
150184610Salfred	DEVMETHOD(bus_driver_added, bus_generic_driver_added),
151184610Salfred
152184610Salfred	/* MII interface */
153188412Sthompsa	DEVMETHOD(miibus_readreg, udav_miibus_readreg),
154188412Sthompsa	DEVMETHOD(miibus_writereg, udav_miibus_writereg),
155188412Sthompsa	DEVMETHOD(miibus_statchg, udav_miibus_statchg),
156184610Salfred
157184610Salfred	{0, 0}
158184610Salfred};
159184610Salfred
160184610Salfredstatic driver_t udav_driver = {
161184610Salfred	.name = "udav",
162184610Salfred	.methods = udav_methods,
163184610Salfred	.size = sizeof(struct udav_softc),
164184610Salfred};
165184610Salfred
166184610Salfredstatic devclass_t udav_devclass;
167184610Salfred
168189275SthompsaDRIVER_MODULE(udav, uhub, udav_driver, udav_devclass, NULL, 0);
169184610SalfredDRIVER_MODULE(miibus, udav, miibus_driver, miibus_devclass, 0, 0);
170188942SthompsaMODULE_DEPEND(udav, uether, 1, 1, 1);
171188942SthompsaMODULE_DEPEND(udav, usb, 1, 1, 1);
172184610SalfredMODULE_DEPEND(udav, ether, 1, 1, 1);
173184610SalfredMODULE_DEPEND(udav, miibus, 1, 1, 1);
174212122SthompsaMODULE_VERSION(udav, 1);
175184610Salfred
176192984Sthompsastatic const struct usb_ether_methods udav_ue_methods = {
177188412Sthompsa	.ue_attach_post = udav_attach_post,
178188412Sthompsa	.ue_start = udav_start,
179188412Sthompsa	.ue_init = udav_init,
180188412Sthompsa	.ue_stop = udav_stop,
181188412Sthompsa	.ue_tick = udav_tick,
182188412Sthompsa	.ue_setmulti = udav_setmulti,
183188412Sthompsa	.ue_setpromisc = udav_setpromisc,
184188412Sthompsa	.ue_mii_upd = udav_ifmedia_upd,
185188412Sthompsa	.ue_mii_sts = udav_ifmedia_status,
186188412Sthompsa};
187188412Sthompsa
188207077Sthompsa#ifdef USB_DEBUG
189184610Salfredstatic int udav_debug = 0;
190184610Salfred
191192502SthompsaSYSCTL_NODE(_hw_usb, OID_AUTO, udav, CTLFLAG_RW, 0, "USB udav");
192192502SthompsaSYSCTL_INT(_hw_usb_udav, OID_AUTO, debug, CTLFLAG_RW, &udav_debug, 0,
193184610Salfred    "Debug level");
194184610Salfred#endif
195184610Salfred
196188412Sthompsa#define	UDAV_SETBIT(sc, reg, x)	\
197188412Sthompsa	udav_csr_write1(sc, reg, udav_csr_read1(sc, reg) | (x))
198184610Salfred
199188412Sthompsa#define	UDAV_CLRBIT(sc, reg, x)	\
200188412Sthompsa	udav_csr_write1(sc, reg, udav_csr_read1(sc, reg) & ~(x))
201184610Salfred
202223486Shselaskystatic const STRUCT_USB_HOST_ID udav_devs[] = {
203184610Salfred	/* ShanTou DM9601 USB NIC */
204184610Salfred	{USB_VPI(USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_DM9601, 0)},
205184610Salfred	/* ShanTou ST268 USB NIC */
206184610Salfred	{USB_VPI(USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_ST268, 0)},
207184610Salfred	/* Corega USB-TXC */
208184610Salfred	{USB_VPI(USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TXC, 0)},
209218864Shselasky	/* ShanTou AMD8515 USB NIC */
210218864Shselasky	{USB_VPI(USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_ADM8515, 0)},
211218864Shselasky	/* Kontron AG USB Ethernet */
212218864Shselasky	{USB_VPI(USB_VENDOR_KONTRON, USB_PRODUCT_KONTRON_DM9601, 0)},
213223288Shselasky	{USB_VPI(USB_VENDOR_KONTRON, USB_PRODUCT_KONTRON_JP1082, 0)},
214184610Salfred};
215184610Salfred
216188412Sthompsastatic void
217192984Sthompsaudav_attach_post(struct usb_ether *ue)
218188412Sthompsa{
219194228Sthompsa	struct udav_softc *sc = uether_getsc(ue);
220188412Sthompsa
221188412Sthompsa	/* reset the adapter */
222188412Sthompsa	udav_reset(sc);
223188412Sthompsa
224188412Sthompsa	/* Get Ethernet Address */
225188412Sthompsa	udav_csr_read(sc, UDAV_PAR, ue->ue_eaddr, ETHER_ADDR_LEN);
226188412Sthompsa}
227188412Sthompsa
228184610Salfredstatic int
229184610Salfredudav_probe(device_t dev)
230184610Salfred{
231192984Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(dev);
232184610Salfred
233192499Sthompsa	if (uaa->usb_mode != USB_MODE_HOST)
234184610Salfred		return (ENXIO);
235188412Sthompsa	if (uaa->info.bConfigIndex != UDAV_CONFIG_INDEX)
236184610Salfred		return (ENXIO);
237188412Sthompsa	if (uaa->info.bIfaceIndex != UDAV_IFACE_INDEX)
238184610Salfred		return (ENXIO);
239188412Sthompsa
240194228Sthompsa	return (usbd_lookup_id_by_uaa(udav_devs, sizeof(udav_devs), uaa));
241184610Salfred}
242184610Salfred
243184610Salfredstatic int
244184610Salfredudav_attach(device_t dev)
245184610Salfred{
246192984Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(dev);
247184610Salfred	struct udav_softc *sc = device_get_softc(dev);
248192984Sthompsa	struct usb_ether *ue = &sc->sc_ue;
249184610Salfred	uint8_t iface_index;
250188412Sthompsa	int error;
251184610Salfred
252184610Salfred	sc->sc_flags = USB_GET_DRIVER_INFO(uaa);
253184610Salfred
254194228Sthompsa	device_set_usb_desc(dev);
255184610Salfred
256188412Sthompsa	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
257184610Salfred
258184610Salfred	iface_index = UDAV_IFACE_INDEX;
259194228Sthompsa	error = usbd_transfer_setup(uaa->device, &iface_index,
260187259Sthompsa	    sc->sc_xfer, udav_config, UDAV_N_TRANSFER, sc, &sc->sc_mtx);
261184610Salfred	if (error) {
262199816Sthompsa		device_printf(dev, "allocating USB transfers failed\n");
263184610Salfred		goto detach;
264184610Salfred	}
265188412Sthompsa
266188412Sthompsa	ue->ue_sc = sc;
267188412Sthompsa	ue->ue_dev = dev;
268188412Sthompsa	ue->ue_udev = uaa->device;
269188412Sthompsa	ue->ue_mtx = &sc->sc_mtx;
270188412Sthompsa	ue->ue_methods = &udav_ue_methods;
271188412Sthompsa
272194228Sthompsa	error = uether_ifattach(ue);
273184610Salfred	if (error) {
274188412Sthompsa		device_printf(dev, "could not attach interface\n");
275184610Salfred		goto detach;
276184610Salfred	}
277184610Salfred
278184610Salfred	return (0);			/* success */
279184610Salfred
280184610Salfreddetach:
281184610Salfred	udav_detach(dev);
282184610Salfred	return (ENXIO);			/* failure */
283184610Salfred}
284184610Salfred
285184610Salfredstatic int
286184610Salfredudav_detach(device_t dev)
287184610Salfred{
288184610Salfred	struct udav_softc *sc = device_get_softc(dev);
289192984Sthompsa	struct usb_ether *ue = &sc->sc_ue;
290184610Salfred
291194228Sthompsa	usbd_transfer_unsetup(sc->sc_xfer, UDAV_N_TRANSFER);
292194228Sthompsa	uether_ifdetach(ue);
293184610Salfred	mtx_destroy(&sc->sc_mtx);
294184610Salfred
295184610Salfred	return (0);
296184610Salfred}
297184610Salfred
298184610Salfred#if 0
299188412Sthompsastatic int
300188412Sthompsaudav_mem_read(struct udav_softc *sc, uint16_t offset, void *buf,
301188412Sthompsa    int len)
302184610Salfred{
303192984Sthompsa	struct usb_device_request req;
304184610Salfred
305184610Salfred	len &= 0xff;
306184610Salfred
307184610Salfred	req.bmRequestType = UT_READ_VENDOR_DEVICE;
308184610Salfred	req.bRequest = UDAV_REQ_MEM_READ;
309184610Salfred	USETW(req.wValue, 0x0000);
310184610Salfred	USETW(req.wIndex, offset);
311184610Salfred	USETW(req.wLength, len);
312184610Salfred
313194228Sthompsa	return (uether_do_request(&sc->sc_ue, &req, buf, 1000));
314184610Salfred}
315184610Salfred
316188412Sthompsastatic int
317188412Sthompsaudav_mem_write(struct udav_softc *sc, uint16_t offset, void *buf,
318188412Sthompsa    int len)
319184610Salfred{
320192984Sthompsa	struct usb_device_request req;
321184610Salfred
322184610Salfred	len &= 0xff;
323184610Salfred
324184610Salfred	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
325184610Salfred	req.bRequest = UDAV_REQ_MEM_WRITE;
326184610Salfred	USETW(req.wValue, 0x0000);
327184610Salfred	USETW(req.wIndex, offset);
328184610Salfred	USETW(req.wLength, len);
329184610Salfred
330194228Sthompsa	return (uether_do_request(&sc->sc_ue, &req, buf, 1000));
331184610Salfred}
332184610Salfred
333188412Sthompsastatic int
334188412Sthompsaudav_mem_write1(struct udav_softc *sc, uint16_t offset,
335184610Salfred    uint8_t ch)
336184610Salfred{
337192984Sthompsa	struct usb_device_request req;
338184610Salfred
339184610Salfred	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
340184610Salfred	req.bRequest = UDAV_REQ_MEM_WRITE1;
341184610Salfred	USETW(req.wValue, ch);
342184610Salfred	USETW(req.wIndex, offset);
343184610Salfred	USETW(req.wLength, 0x0000);
344184610Salfred
345194228Sthompsa	return (uether_do_request(&sc->sc_ue, &req, NULL, 1000));
346184610Salfred}
347184610Salfred#endif
348184610Salfred
349188412Sthompsastatic int
350188412Sthompsaudav_csr_read(struct udav_softc *sc, uint16_t offset, void *buf, int len)
351184610Salfred{
352192984Sthompsa	struct usb_device_request req;
353184610Salfred
354184610Salfred	len &= 0xff;
355184610Salfred
356184610Salfred	req.bmRequestType = UT_READ_VENDOR_DEVICE;
357184610Salfred	req.bRequest = UDAV_REQ_REG_READ;
358184610Salfred	USETW(req.wValue, 0x0000);
359184610Salfred	USETW(req.wIndex, offset);
360184610Salfred	USETW(req.wLength, len);
361184610Salfred
362194228Sthompsa	return (uether_do_request(&sc->sc_ue, &req, buf, 1000));
363184610Salfred}
364184610Salfred
365188412Sthompsastatic int
366188412Sthompsaudav_csr_write(struct udav_softc *sc, uint16_t offset, void *buf, int len)
367184610Salfred{
368192984Sthompsa	struct usb_device_request req;
369184610Salfred
370184610Salfred	offset &= 0xff;
371184610Salfred	len &= 0xff;
372184610Salfred
373184610Salfred	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
374184610Salfred	req.bRequest = UDAV_REQ_REG_WRITE;
375184610Salfred	USETW(req.wValue, 0x0000);
376184610Salfred	USETW(req.wIndex, offset);
377184610Salfred	USETW(req.wLength, len);
378184610Salfred
379194228Sthompsa	return (uether_do_request(&sc->sc_ue, &req, buf, 1000));
380184610Salfred}
381184610Salfred
382184610Salfredstatic uint8_t
383188412Sthompsaudav_csr_read1(struct udav_softc *sc, uint16_t offset)
384184610Salfred{
385184610Salfred	uint8_t val;
386184610Salfred
387188412Sthompsa	udav_csr_read(sc, offset, &val, 1);
388184610Salfred	return (val);
389184610Salfred}
390184610Salfred
391188412Sthompsastatic int
392188412Sthompsaudav_csr_write1(struct udav_softc *sc, uint16_t offset,
393184610Salfred    uint8_t ch)
394184610Salfred{
395192984Sthompsa	struct usb_device_request req;
396184610Salfred
397184610Salfred	offset &= 0xff;
398184610Salfred
399184610Salfred	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
400184610Salfred	req.bRequest = UDAV_REQ_REG_WRITE1;
401184610Salfred	USETW(req.wValue, ch);
402184610Salfred	USETW(req.wIndex, offset);
403184610Salfred	USETW(req.wLength, 0x0000);
404184610Salfred
405194228Sthompsa	return (uether_do_request(&sc->sc_ue, &req, NULL, 1000));
406184610Salfred}
407184610Salfred
408184610Salfredstatic void
409192984Sthompsaudav_init(struct usb_ether *ue)
410184610Salfred{
411188412Sthompsa	struct udav_softc *sc = ue->ue_sc;
412194228Sthompsa	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
413184610Salfred
414188412Sthompsa	UDAV_LOCK_ASSERT(sc, MA_OWNED);
415184610Salfred
416184610Salfred	/*
417184610Salfred	 * Cancel pending I/O
418184610Salfred	 */
419188412Sthompsa	udav_stop(ue);
420184610Salfred
421184610Salfred	/* set MAC address */
422188412Sthompsa	udav_csr_write(sc, UDAV_PAR, IF_LLADDR(ifp), ETHER_ADDR_LEN);
423184610Salfred
424184610Salfred	/* initialize network control register */
425184610Salfred
426184610Salfred	/* disable loopback  */
427188412Sthompsa	UDAV_CLRBIT(sc, UDAV_NCR, UDAV_NCR_LBK0 | UDAV_NCR_LBK1);
428184610Salfred
429184610Salfred	/* Initialize RX control register */
430188412Sthompsa	UDAV_SETBIT(sc, UDAV_RCR, UDAV_RCR_DIS_LONG | UDAV_RCR_DIS_CRC);
431184610Salfred
432184610Salfred	/* load multicast filter and update promiscious mode bit */
433188412Sthompsa	udav_setpromisc(ue);
434184610Salfred
435184610Salfred	/* enable RX */
436188412Sthompsa	UDAV_SETBIT(sc, UDAV_RCR, UDAV_RCR_RXEN);
437184610Salfred
438184610Salfred	/* clear POWER_DOWN state of internal PHY */
439188412Sthompsa	UDAV_SETBIT(sc, UDAV_GPCR, UDAV_GPCR_GEP_CNTL0);
440188412Sthompsa	UDAV_CLRBIT(sc, UDAV_GPR, UDAV_GPR_GEPIO0);
441184610Salfred
442194677Sthompsa	usbd_xfer_set_stall(sc->sc_xfer[UDAV_BULK_DT_WR]);
443184610Salfred
444188412Sthompsa	ifp->if_drv_flags |= IFF_DRV_RUNNING;
445188412Sthompsa	udav_start(ue);
446184610Salfred}
447184610Salfred
448184610Salfredstatic void
449188412Sthompsaudav_reset(struct udav_softc *sc)
450184610Salfred{
451188412Sthompsa	int i;
452184610Salfred
453184610Salfred	/* Select PHY */
454184610Salfred#if 1
455184610Salfred	/*
456184610Salfred	 * XXX: force select internal phy.
457184610Salfred	 *	external phy routines are not tested.
458184610Salfred	 */
459188412Sthompsa	UDAV_CLRBIT(sc, UDAV_NCR, UDAV_NCR_EXT_PHY);
460184610Salfred#else
461188412Sthompsa	if (sc->sc_flags & UDAV_EXT_PHY)
462188412Sthompsa		UDAV_SETBIT(sc, UDAV_NCR, UDAV_NCR_EXT_PHY);
463188412Sthompsa	else
464188412Sthompsa		UDAV_CLRBIT(sc, UDAV_NCR, UDAV_NCR_EXT_PHY);
465184610Salfred#endif
466184610Salfred
467188412Sthompsa	UDAV_SETBIT(sc, UDAV_NCR, UDAV_NCR_RST);
468184610Salfred
469188412Sthompsa	for (i = 0; i < UDAV_TX_TIMEOUT; i++) {
470188412Sthompsa		if (!(udav_csr_read1(sc, UDAV_NCR) & UDAV_NCR_RST))
471184610Salfred			break;
472194228Sthompsa		if (uether_pause(&sc->sc_ue, hz / 100))
473188412Sthompsa			break;
474184610Salfred	}
475184610Salfred
476194228Sthompsa	uether_pause(&sc->sc_ue, hz / 100);
477184610Salfred}
478184610Salfred
479184610Salfred#define	UDAV_BITS	6
480184610Salfredstatic void
481192984Sthompsaudav_setmulti(struct usb_ether *ue)
482184610Salfred{
483188412Sthompsa	struct udav_softc *sc = ue->ue_sc;
484194228Sthompsa	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
485188412Sthompsa	struct ifmultiaddr *ifma;
486188412Sthompsa	uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
487188412Sthompsa	int h = 0;
488184610Salfred
489188412Sthompsa	UDAV_LOCK_ASSERT(sc, MA_OWNED);
490184610Salfred
491188412Sthompsa	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
492188412Sthompsa		UDAV_SETBIT(sc, UDAV_RCR, UDAV_RCR_ALL|UDAV_RCR_PRMSC);
493188412Sthompsa		return;
494188412Sthompsa	}
495188412Sthompsa
496188412Sthompsa	/* first, zot all the existing hash bits */
497188412Sthompsa	memset(hashtbl, 0x00, sizeof(hashtbl));
498188412Sthompsa	hashtbl[7] |= 0x80;	/* broadcast address */
499188412Sthompsa	udav_csr_write(sc, UDAV_MAR, hashtbl, sizeof(hashtbl));
500188412Sthompsa
501188412Sthompsa	/* now program new ones */
502195049Srwatson	if_maddr_rlock(ifp);
503188412Sthompsa	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
504188412Sthompsa	{
505188412Sthompsa		if (ifma->ifma_addr->sa_family != AF_LINK)
506188412Sthompsa			continue;
507188412Sthompsa		h = ether_crc32_be(LLADDR((struct sockaddr_dl *)
508188412Sthompsa		    ifma->ifma_addr), ETHER_ADDR_LEN) >> 26;
509188412Sthompsa		hashtbl[h / 8] |= 1 << (h % 8);
510188412Sthompsa	}
511195049Srwatson	if_maddr_runlock(ifp);
512188412Sthompsa
513188412Sthompsa	/* disable all multicast */
514188412Sthompsa	UDAV_CLRBIT(sc, UDAV_RCR, UDAV_RCR_ALL);
515188412Sthompsa
516188412Sthompsa	/* write hash value to the register */
517188412Sthompsa	udav_csr_write(sc, UDAV_MAR, hashtbl, sizeof(hashtbl));
518184610Salfred}
519184610Salfred
520184610Salfredstatic void
521192984Sthompsaudav_setpromisc(struct usb_ether *ue)
522184610Salfred{
523188412Sthompsa	struct udav_softc *sc = ue->ue_sc;
524194228Sthompsa	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
525184610Salfred	uint8_t rxmode;
526184610Salfred
527188412Sthompsa	rxmode = udav_csr_read1(sc, UDAV_RCR);
528184610Salfred	rxmode &= ~(UDAV_RCR_ALL | UDAV_RCR_PRMSC);
529184610Salfred
530188412Sthompsa	if (ifp->if_flags & IFF_PROMISC)
531184610Salfred		rxmode |= UDAV_RCR_ALL | UDAV_RCR_PRMSC;
532188412Sthompsa	else if (ifp->if_flags & IFF_ALLMULTI)
533184610Salfred		rxmode |= UDAV_RCR_ALL;
534184610Salfred
535184610Salfred	/* write new mode bits */
536188412Sthompsa	udav_csr_write1(sc, UDAV_RCR, rxmode);
537184610Salfred}
538184610Salfred
539184610Salfredstatic void
540192984Sthompsaudav_start(struct usb_ether *ue)
541184610Salfred{
542188412Sthompsa	struct udav_softc *sc = ue->ue_sc;
543184610Salfred
544188412Sthompsa	/*
545188412Sthompsa	 * start the USB transfers, if not already started:
546188412Sthompsa	 */
547194228Sthompsa	usbd_transfer_start(sc->sc_xfer[UDAV_INTR_DT_RD]);
548194228Sthompsa	usbd_transfer_start(sc->sc_xfer[UDAV_BULK_DT_RD]);
549194228Sthompsa	usbd_transfer_start(sc->sc_xfer[UDAV_BULK_DT_WR]);
550184610Salfred}
551184610Salfred
552184610Salfredstatic void
553194677Sthompsaudav_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
554184610Salfred{
555194677Sthompsa	struct udav_softc *sc = usbd_xfer_softc(xfer);
556194228Sthompsa	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
557194677Sthompsa	struct usb_page_cache *pc;
558184610Salfred	struct mbuf *m;
559188412Sthompsa	int extra_len;
560188412Sthompsa	int temp_len;
561184610Salfred	uint8_t buf[2];
562184610Salfred
563184610Salfred	switch (USB_GET_STATE(xfer)) {
564184610Salfred	case USB_ST_TRANSFERRED:
565184610Salfred		DPRINTFN(11, "transfer complete\n");
566184610Salfred		ifp->if_opackets++;
567184610Salfred
568188412Sthompsa		/* FALLTHROUGH */
569184610Salfred	case USB_ST_SETUP:
570188412Sthompsatr_setup:
571188412Sthompsa		if ((sc->sc_flags & UDAV_FLAG_LINK) == 0) {
572184610Salfred			/*
573184610Salfred			 * don't send anything if there is no link !
574184610Salfred			 */
575188412Sthompsa			return;
576184610Salfred		}
577184610Salfred		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
578184610Salfred
579188412Sthompsa		if (m == NULL)
580188412Sthompsa			return;
581188412Sthompsa		if (m->m_pkthdr.len > MCLBYTES)
582184610Salfred			m->m_pkthdr.len = MCLBYTES;
583184610Salfred		if (m->m_pkthdr.len < UDAV_MIN_FRAME_LEN) {
584184610Salfred			extra_len = UDAV_MIN_FRAME_LEN - m->m_pkthdr.len;
585184610Salfred		} else {
586184610Salfred			extra_len = 0;
587184610Salfred		}
588184610Salfred
589184610Salfred		temp_len = (m->m_pkthdr.len + extra_len);
590184610Salfred
591184610Salfred		/*
592184610Salfred		 * the frame length is specified in the first 2 bytes of the
593184610Salfred		 * buffer
594184610Salfred		 */
595184610Salfred		buf[0] = (uint8_t)(temp_len);
596184610Salfred		buf[1] = (uint8_t)(temp_len >> 8);
597184610Salfred
598184610Salfred		temp_len += 2;
599184610Salfred
600194677Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
601194677Sthompsa		usbd_copy_in(pc, 0, buf, 2);
602194677Sthompsa		usbd_m_copy_in(pc, 2, m, 0, m->m_pkthdr.len);
603184610Salfred
604194677Sthompsa		if (extra_len)
605194677Sthompsa			usbd_frame_zero(pc, temp_len - extra_len, extra_len);
606184610Salfred		/*
607184610Salfred		 * if there's a BPF listener, bounce a copy
608184610Salfred		 * of this frame to him:
609184610Salfred		 */
610184610Salfred		BPF_MTAP(ifp, m);
611184610Salfred
612184610Salfred		m_freem(m);
613184610Salfred
614194677Sthompsa		usbd_xfer_set_frame_len(xfer, 0, temp_len);
615194228Sthompsa		usbd_transfer_submit(xfer);
616184610Salfred		return;
617184610Salfred
618184610Salfred	default:			/* Error */
619184610Salfred		DPRINTFN(11, "transfer error, %s\n",
620194677Sthompsa		    usbd_errstr(error));
621184610Salfred
622188412Sthompsa		ifp->if_oerrors++;
623188412Sthompsa
624194677Sthompsa		if (error != USB_ERR_CANCELLED) {
625184610Salfred			/* try to clear stall first */
626194677Sthompsa			usbd_xfer_set_stall(xfer);
627188412Sthompsa			goto tr_setup;
628184610Salfred		}
629184610Salfred		return;
630184610Salfred	}
631184610Salfred}
632184610Salfred
633184610Salfredstatic void
634194677Sthompsaudav_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
635184610Salfred{
636194677Sthompsa	struct udav_softc *sc = usbd_xfer_softc(xfer);
637192984Sthompsa	struct usb_ether *ue = &sc->sc_ue;
638194228Sthompsa	struct ifnet *ifp = uether_getifp(ue);
639194677Sthompsa	struct usb_page_cache *pc;
640188412Sthompsa	struct udav_rxpkt stat;
641188412Sthompsa	int len;
642194677Sthompsa	int actlen;
643184610Salfred
644194677Sthompsa	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
645194677Sthompsa
646184610Salfred	switch (USB_GET_STATE(xfer)) {
647184610Salfred	case USB_ST_TRANSFERRED:
648184610Salfred
649194677Sthompsa		if (actlen < sizeof(stat) + ETHER_CRC_LEN) {
650184610Salfred			ifp->if_ierrors++;
651184610Salfred			goto tr_setup;
652184610Salfred		}
653194677Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
654194677Sthompsa		usbd_copy_out(pc, 0, &stat, sizeof(stat));
655194677Sthompsa		actlen -= sizeof(stat);
656194677Sthompsa		len = min(actlen, le16toh(stat.pktlen));
657188412Sthompsa		len -= ETHER_CRC_LEN;
658184610Salfred
659188412Sthompsa		if (stat.rxstat & UDAV_RSR_LCS) {
660184610Salfred			ifp->if_collisions++;
661184610Salfred			goto tr_setup;
662184610Salfred		}
663188412Sthompsa		if (stat.rxstat & UDAV_RSR_ERR) {
664184610Salfred			ifp->if_ierrors++;
665184610Salfred			goto tr_setup;
666184610Salfred		}
667194677Sthompsa		uether_rxbuf(ue, pc, sizeof(stat), len);
668188412Sthompsa		/* FALLTHROUGH */
669184610Salfred	case USB_ST_SETUP:
670184610Salfredtr_setup:
671194677Sthompsa		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
672194228Sthompsa		usbd_transfer_submit(xfer);
673194228Sthompsa		uether_rxflush(ue);
674184610Salfred		return;
675184610Salfred
676184610Salfred	default:			/* Error */
677188412Sthompsa		DPRINTF("bulk read error, %s\n",
678194677Sthompsa		    usbd_errstr(error));
679188412Sthompsa
680194677Sthompsa		if (error != USB_ERR_CANCELLED) {
681184610Salfred			/* try to clear stall first */
682194677Sthompsa			usbd_xfer_set_stall(xfer);
683188412Sthompsa			goto tr_setup;
684184610Salfred		}
685184610Salfred		return;
686184610Salfred	}
687184610Salfred}
688184610Salfred
689184610Salfredstatic void
690194677Sthompsaudav_intr_callback(struct usb_xfer *xfer, usb_error_t error)
691184610Salfred{
692184610Salfred	switch (USB_GET_STATE(xfer)) {
693184610Salfred	case USB_ST_TRANSFERRED:
694184610Salfred	case USB_ST_SETUP:
695188412Sthompsatr_setup:
696194677Sthompsa		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
697194228Sthompsa		usbd_transfer_submit(xfer);
698184610Salfred		return;
699184610Salfred
700184610Salfred	default:			/* Error */
701194677Sthompsa		if (error != USB_ERR_CANCELLED) {
702188412Sthompsa			/* try to clear stall first */
703194677Sthompsa			usbd_xfer_set_stall(xfer);
704188412Sthompsa			goto tr_setup;
705184610Salfred		}
706184610Salfred		return;
707184610Salfred	}
708184610Salfred}
709184610Salfred
710184610Salfredstatic void
711192984Sthompsaudav_stop(struct usb_ether *ue)
712184610Salfred{
713188412Sthompsa	struct udav_softc *sc = ue->ue_sc;
714194228Sthompsa	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
715184610Salfred
716188412Sthompsa	UDAV_LOCK_ASSERT(sc, MA_OWNED);
717184610Salfred
718188412Sthompsa	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
719188412Sthompsa	sc->sc_flags &= ~UDAV_FLAG_LINK;
720184610Salfred
721184610Salfred	/*
722184610Salfred	 * stop all the transfers, if not already stopped:
723184610Salfred	 */
724194228Sthompsa	usbd_transfer_stop(sc->sc_xfer[UDAV_BULK_DT_WR]);
725194228Sthompsa	usbd_transfer_stop(sc->sc_xfer[UDAV_BULK_DT_RD]);
726194228Sthompsa	usbd_transfer_stop(sc->sc_xfer[UDAV_INTR_DT_RD]);
727184610Salfred
728188412Sthompsa	udav_reset(sc);
729184610Salfred}
730184610Salfred
731184610Salfredstatic int
732188412Sthompsaudav_ifmedia_upd(struct ifnet *ifp)
733184610Salfred{
734184610Salfred	struct udav_softc *sc = ifp->if_softc;
735184610Salfred	struct mii_data *mii = GET_MII(sc);
736221407Smarius	struct mii_softc *miisc;
737184610Salfred
738188412Sthompsa	UDAV_LOCK_ASSERT(sc, MA_OWNED);
739184610Salfred
740188412Sthompsa        sc->sc_flags &= ~UDAV_FLAG_LINK;
741221407Smarius	LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
742221407Smarius		PHY_RESET(miisc);
743184610Salfred	mii_mediachg(mii);
744188412Sthompsa	return (0);
745184610Salfred}
746184610Salfred
747184610Salfredstatic void
748188412Sthompsaudav_ifmedia_status(struct ifnet *ifp, struct ifmediareq *ifmr)
749184610Salfred{
750184610Salfred	struct udav_softc *sc = ifp->if_softc;
751188412Sthompsa	struct mii_data *mii = GET_MII(sc);
752184610Salfred
753188412Sthompsa	UDAV_LOCK(sc);
754188412Sthompsa	mii_pollstat(mii);
755188412Sthompsa	UDAV_UNLOCK(sc);
756188412Sthompsa	ifmr->ifm_active = mii->mii_media_active;
757188412Sthompsa	ifmr->ifm_status = mii->mii_media_status;
758184610Salfred}
759184610Salfred
760184610Salfredstatic void
761192984Sthompsaudav_tick(struct usb_ether *ue)
762184610Salfred{
763188412Sthompsa	struct udav_softc *sc = ue->ue_sc;
764184610Salfred	struct mii_data *mii = GET_MII(sc);
765184610Salfred
766188412Sthompsa	UDAV_LOCK_ASSERT(sc, MA_OWNED);
767188412Sthompsa
768184610Salfred	mii_tick(mii);
769188412Sthompsa	if ((sc->sc_flags & UDAV_FLAG_LINK) == 0
770188412Sthompsa	    && mii->mii_media_status & IFM_ACTIVE &&
771188412Sthompsa	    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
772188412Sthompsa		sc->sc_flags |= UDAV_FLAG_LINK;
773188412Sthompsa		udav_start(ue);
774184610Salfred	}
775184610Salfred}
776184610Salfred
777184610Salfredstatic int
778188412Sthompsaudav_miibus_readreg(device_t dev, int phy, int reg)
779184610Salfred{
780184610Salfred	struct udav_softc *sc = device_get_softc(dev);
781184610Salfred	uint16_t data16;
782184610Salfred	uint8_t val[2];
783188412Sthompsa	int locked;
784184610Salfred
785184610Salfred	/* XXX: one PHY only for the internal PHY */
786188412Sthompsa	if (phy != 0)
787184610Salfred		return (0);
788184610Salfred
789188412Sthompsa	locked = mtx_owned(&sc->sc_mtx);
790188412Sthompsa	if (!locked)
791188412Sthompsa		UDAV_LOCK(sc);
792188412Sthompsa
793184610Salfred	/* select internal PHY and set PHY register address */
794188412Sthompsa	udav_csr_write1(sc, UDAV_EPAR,
795184610Salfred	    UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK));
796184610Salfred
797184610Salfred	/* select PHY operation and start read command */
798188412Sthompsa	udav_csr_write1(sc, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRR);
799184610Salfred
800184610Salfred	/* XXX: should we wait? */
801184610Salfred
802184610Salfred	/* end read command */
803188412Sthompsa	UDAV_CLRBIT(sc, UDAV_EPCR, UDAV_EPCR_ERPRR);
804184610Salfred
805184610Salfred	/* retrieve the result from data registers */
806188412Sthompsa	udav_csr_read(sc, UDAV_EPDRL, val, 2);
807184610Salfred
808184610Salfred	data16 = (val[0] | (val[1] << 8));
809184610Salfred
810184610Salfred	DPRINTFN(11, "phy=%d reg=0x%04x => 0x%04x\n",
811184610Salfred	    phy, reg, data16);
812184610Salfred
813188412Sthompsa	if (!locked)
814188412Sthompsa		UDAV_UNLOCK(sc);
815184610Salfred	return (data16);
816184610Salfred}
817184610Salfred
818184610Salfredstatic int
819188412Sthompsaudav_miibus_writereg(device_t dev, int phy, int reg, int data)
820184610Salfred{
821184610Salfred	struct udav_softc *sc = device_get_softc(dev);
822184610Salfred	uint8_t val[2];
823188412Sthompsa	int locked;
824184610Salfred
825184610Salfred	/* XXX: one PHY only for the internal PHY */
826188412Sthompsa	if (phy != 0)
827184610Salfred		return (0);
828184610Salfred
829188412Sthompsa	locked = mtx_owned(&sc->sc_mtx);
830188412Sthompsa	if (!locked)
831188412Sthompsa		UDAV_LOCK(sc);
832188412Sthompsa
833184610Salfred	/* select internal PHY and set PHY register address */
834188412Sthompsa	udav_csr_write1(sc, UDAV_EPAR,
835184610Salfred	    UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK));
836184610Salfred
837184610Salfred	/* put the value to the data registers */
838184610Salfred	val[0] = (data & 0xff);
839184610Salfred	val[1] = (data >> 8) & 0xff;
840188412Sthompsa	udav_csr_write(sc, UDAV_EPDRL, val, 2);
841184610Salfred
842184610Salfred	/* select PHY operation and start write command */
843188412Sthompsa	udav_csr_write1(sc, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRW);
844184610Salfred
845184610Salfred	/* XXX: should we wait? */
846184610Salfred
847184610Salfred	/* end write command */
848188412Sthompsa	UDAV_CLRBIT(sc, UDAV_EPCR, UDAV_EPCR_ERPRW);
849184610Salfred
850188412Sthompsa	if (!locked)
851188412Sthompsa		UDAV_UNLOCK(sc);
852184610Salfred	return (0);
853184610Salfred}
854184610Salfred
855184610Salfredstatic void
856188412Sthompsaudav_miibus_statchg(device_t dev)
857184610Salfred{
858184610Salfred	/* nothing to do */
859184610Salfred}
860