xref: /dragonfly/sys/bus/u4b/net/if_mos.c (revision 2b3f93ea)
112bd3c8bSSascha Wildner /*-
212bd3c8bSSascha Wildner  * Copyright (c) 2011 Rick van der Zwet <info@rickvanderzwet.nl>
312bd3c8bSSascha Wildner  *
412bd3c8bSSascha Wildner  * Permission to use, copy, modify, and distribute this software for any
512bd3c8bSSascha Wildner  * purpose with or without fee is hereby granted, provided that the above
612bd3c8bSSascha Wildner  * copyright notice and this permission notice appear in all copies.
712bd3c8bSSascha Wildner  *
812bd3c8bSSascha Wildner  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
912bd3c8bSSascha Wildner  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1012bd3c8bSSascha Wildner  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1112bd3c8bSSascha Wildner  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212bd3c8bSSascha Wildner  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1312bd3c8bSSascha Wildner  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1412bd3c8bSSascha Wildner  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1512bd3c8bSSascha Wildner  */
1612bd3c8bSSascha Wildner 
1712bd3c8bSSascha Wildner /*-
1812bd3c8bSSascha Wildner  * Copyright (c) 2008 Johann Christian Rode <jcrode@gmx.net>
1912bd3c8bSSascha Wildner  *
2012bd3c8bSSascha Wildner  * Permission to use, copy, modify, and distribute this software for any
2112bd3c8bSSascha Wildner  * purpose with or without fee is hereby granted, provided that the above
2212bd3c8bSSascha Wildner  * copyright notice and this permission notice appear in all copies.
2312bd3c8bSSascha Wildner  *
2412bd3c8bSSascha Wildner  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
2512bd3c8bSSascha Wildner  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
2612bd3c8bSSascha Wildner  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
2712bd3c8bSSascha Wildner  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
2812bd3c8bSSascha Wildner  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
2912bd3c8bSSascha Wildner  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
3012bd3c8bSSascha Wildner  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
3112bd3c8bSSascha Wildner  */
3212bd3c8bSSascha Wildner 
3312bd3c8bSSascha Wildner /*-
3412bd3c8bSSascha Wildner  * Copyright (c) 2005, 2006, 2007 Jonathan Gray <jsg@openbsd.org>
3512bd3c8bSSascha Wildner  *
3612bd3c8bSSascha Wildner  * Permission to use, copy, modify, and distribute this software for any
3712bd3c8bSSascha Wildner  * purpose with or without fee is hereby granted, provided that the above
3812bd3c8bSSascha Wildner  * copyright notice and this permission notice appear in all copies.
3912bd3c8bSSascha Wildner  *
4012bd3c8bSSascha Wildner  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
4112bd3c8bSSascha Wildner  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
4212bd3c8bSSascha Wildner  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
4312bd3c8bSSascha Wildner  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
4412bd3c8bSSascha Wildner  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
4512bd3c8bSSascha Wildner  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
4612bd3c8bSSascha Wildner  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
4712bd3c8bSSascha Wildner  */
4812bd3c8bSSascha Wildner 
4912bd3c8bSSascha Wildner /*-
5012bd3c8bSSascha Wildner  * Copyright (c) 1997, 1998, 1999, 2000-2003
5112bd3c8bSSascha Wildner  *	Bill Paul <wpaul@windriver.com>.  All rights reserved.
5212bd3c8bSSascha Wildner  *
5312bd3c8bSSascha Wildner  * Redistribution and use in source and binary forms, with or without
5412bd3c8bSSascha Wildner  * modification, are permitted provided that the following conditions
5512bd3c8bSSascha Wildner  * are met:
5612bd3c8bSSascha Wildner  * 1. Redistributions of source code must retain the above copyright
5712bd3c8bSSascha Wildner  *    notice, this list of conditions and the following disclaimer.
5812bd3c8bSSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
5912bd3c8bSSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
6012bd3c8bSSascha Wildner  *    documentation and/or other materials provided with the distribution.
6112bd3c8bSSascha Wildner  * 3. All advertising materials mentioning features or use of this software
6212bd3c8bSSascha Wildner  *    must display the following acknowledgement:
6312bd3c8bSSascha Wildner  *	This product includes software developed by Bill Paul.
6412bd3c8bSSascha Wildner  * 4. Neither the name of the author nor the names of any co-contributors
6512bd3c8bSSascha Wildner  *    may be used to endorse or promote products derived from this software
6612bd3c8bSSascha Wildner  *    without specific prior written permission.
6712bd3c8bSSascha Wildner  *
6812bd3c8bSSascha Wildner  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
6912bd3c8bSSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
7012bd3c8bSSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7112bd3c8bSSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
7212bd3c8bSSascha Wildner  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
7312bd3c8bSSascha Wildner  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
7412bd3c8bSSascha Wildner  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
7512bd3c8bSSascha Wildner  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
7612bd3c8bSSascha Wildner  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
7712bd3c8bSSascha Wildner  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
7812bd3c8bSSascha Wildner  * THE POSSIBILITY OF SUCH DAMAGE.
79f8577199SSascha Wildner  *
80f8577199SSascha Wildner  * $FreeBSD: head/sys/dev/usb/net/if_mos.c 271832 2014-09-18 21:09:22Z glebius $
8112bd3c8bSSascha Wildner  */
8212bd3c8bSSascha Wildner 
8312bd3c8bSSascha Wildner /*
84f8577199SSascha Wildner  * Moschip MCS7730/MCS7830/MCS7832 USB to Ethernet controller
8512bd3c8bSSascha Wildner  * The datasheet is available at the following URL:
8612bd3c8bSSascha Wildner  * http://www.moschip.com/data/products/MCS7830/Data%20Sheet_7830.pdf
8712bd3c8bSSascha Wildner  */
8812bd3c8bSSascha Wildner 
8912bd3c8bSSascha Wildner /*
9012bd3c8bSSascha Wildner  * The FreeBSD if_mos.c driver is based on various different sources:
9112bd3c8bSSascha Wildner  * The vendor provided driver at the following URL:
9212bd3c8bSSascha Wildner  * http://www.moschip.com/data/products/MCS7830/Driver_FreeBSD_7830.tar.gz
9312bd3c8bSSascha Wildner  *
9412bd3c8bSSascha Wildner  * Mixed together with the OpenBSD if_mos.c driver for validation and checking
9512bd3c8bSSascha Wildner  * and the FreeBSD if_reu.c as reference for the USB Ethernet framework.
9612bd3c8bSSascha Wildner  */
9712bd3c8bSSascha Wildner 
9812bd3c8bSSascha Wildner #include <sys/stdint.h>
9912bd3c8bSSascha Wildner #include <sys/param.h>
10012bd3c8bSSascha Wildner #include <sys/queue.h>
10112bd3c8bSSascha Wildner #include <sys/types.h>
10212bd3c8bSSascha Wildner #include <sys/systm.h>
103f8577199SSascha Wildner #include <sys/socket.h>
10412bd3c8bSSascha Wildner #include <sys/kernel.h>
10512bd3c8bSSascha Wildner #include <sys/bus.h>
10612bd3c8bSSascha Wildner #include <sys/module.h>
10712bd3c8bSSascha Wildner #include <sys/lock.h>
10812bd3c8bSSascha Wildner #include <sys/condvar.h>
10912bd3c8bSSascha Wildner #include <sys/sysctl.h>
11012bd3c8bSSascha Wildner #include <sys/unistd.h>
11112bd3c8bSSascha Wildner #include <sys/callout.h>
11212bd3c8bSSascha Wildner #include <sys/malloc.h>
113*2b3f93eaSMatthew Dillon #include <sys/caps.h>
11412bd3c8bSSascha Wildner 
115f8577199SSascha Wildner #include <net/if.h>
116f8577199SSascha Wildner #include <net/if_var.h>
117559d4eaeSSascha Wildner #include <net/ifq_var.h>
118559d4eaeSSascha Wildner 
119559d4eaeSSascha Wildner #include <bus/u4b/usb.h>
120559d4eaeSSascha Wildner #include <bus/u4b/usbdi.h>
121559d4eaeSSascha Wildner #include <bus/u4b/usbdi_util.h>
12212bd3c8bSSascha Wildner #include "usbdevs.h"
12312bd3c8bSSascha Wildner 
12412bd3c8bSSascha Wildner #define	USB_DEBUG_VAR mos_debug
125559d4eaeSSascha Wildner #include <bus/u4b/usb_debug.h>
126559d4eaeSSascha Wildner #include <bus/u4b/usb_process.h>
12712bd3c8bSSascha Wildner 
128559d4eaeSSascha Wildner #include <bus/u4b/net/usb_ethernet.h>
12912bd3c8bSSascha Wildner 
130559d4eaeSSascha Wildner //#include <bus/u4b/net/if_mosreg.h>
13112bd3c8bSSascha Wildner #include "if_mosreg.h"
13212bd3c8bSSascha Wildner 
13312bd3c8bSSascha Wildner #ifdef USB_DEBUG
13412bd3c8bSSascha Wildner static int mos_debug = 0;
13512bd3c8bSSascha Wildner 
13612bd3c8bSSascha Wildner static SYSCTL_NODE(_hw_usb, OID_AUTO, mos, CTLFLAG_RW, 0, "USB mos");
137a9b765b7SSascha Wildner SYSCTL_INT(_hw_usb_mos, OID_AUTO, debug, CTLFLAG_RW, &mos_debug, 0,
13812bd3c8bSSascha Wildner     "Debug level");
13912bd3c8bSSascha Wildner #endif
14012bd3c8bSSascha Wildner 
14112bd3c8bSSascha Wildner #define MOS_DPRINTFN(fmt,...) \
1427fd4e1a1SSascha Wildner   DPRINTF("mos: %s: " fmt "\n",__func__,## __VA_ARGS__)
14312bd3c8bSSascha Wildner 
14412bd3c8bSSascha Wildner #define	USB_PRODUCT_MOSCHIP_MCS7730	0x7730
14512bd3c8bSSascha Wildner #define	USB_PRODUCT_SITECOMEU_LN030	0x0021
14612bd3c8bSSascha Wildner 
14712bd3c8bSSascha Wildner 
14812bd3c8bSSascha Wildner 
14912bd3c8bSSascha Wildner /* Various supported device vendors/products. */
15012bd3c8bSSascha Wildner static const STRUCT_USB_HOST_ID mos_devs[] = {
15112bd3c8bSSascha Wildner 	{USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7730, MCS7730)},
15212bd3c8bSSascha Wildner 	{USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7830, MCS7830)},
153f8577199SSascha Wildner 	{USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7832, MCS7832)},
15412bd3c8bSSascha Wildner 	{USB_VPI(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN030, MCS7830)},
15512bd3c8bSSascha Wildner };
15612bd3c8bSSascha Wildner 
15712bd3c8bSSascha Wildner static int mos_probe(device_t dev);
15812bd3c8bSSascha Wildner static int mos_attach(device_t dev);
15912bd3c8bSSascha Wildner static void mos_attach_post(struct usb_ether *ue);
16012bd3c8bSSascha Wildner static int mos_detach(device_t dev);
16112bd3c8bSSascha Wildner 
16212bd3c8bSSascha Wildner static void mos_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error);
16312bd3c8bSSascha Wildner static void mos_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error);
16412bd3c8bSSascha Wildner static void mos_intr_callback(struct usb_xfer *xfer, usb_error_t error);
16512bd3c8bSSascha Wildner static void mos_tick(struct usb_ether *);
16612bd3c8bSSascha Wildner static void mos_start(struct usb_ether *);
16712bd3c8bSSascha Wildner static void mos_init(struct usb_ether *);
16812bd3c8bSSascha Wildner static void mos_chip_init(struct mos_softc *);
16912bd3c8bSSascha Wildner static void mos_stop(struct usb_ether *);
17012bd3c8bSSascha Wildner static int mos_miibus_readreg(device_t, int, int);
17112bd3c8bSSascha Wildner static int mos_miibus_writereg(device_t, int, int, int);
17212bd3c8bSSascha Wildner static void mos_miibus_statchg(device_t);
17312bd3c8bSSascha Wildner static int mos_ifmedia_upd(struct ifnet *);
17412bd3c8bSSascha Wildner static void mos_ifmedia_sts(struct ifnet *, struct ifmediareq *);
17512bd3c8bSSascha Wildner static void mos_reset(struct mos_softc *sc);
17612bd3c8bSSascha Wildner 
17712bd3c8bSSascha Wildner static int mos_reg_read_1(struct mos_softc *, int);
17812bd3c8bSSascha Wildner static int mos_reg_read_2(struct mos_softc *, int);
17912bd3c8bSSascha Wildner static int mos_reg_write_1(struct mos_softc *, int, int);
18012bd3c8bSSascha Wildner static int mos_reg_write_2(struct mos_softc *, int, int);
18112bd3c8bSSascha Wildner static int mos_readmac(struct mos_softc *, uint8_t *);
18212bd3c8bSSascha Wildner static int mos_writemac(struct mos_softc *, uint8_t *);
18312bd3c8bSSascha Wildner static int mos_write_mcast(struct mos_softc *, u_char *);
18412bd3c8bSSascha Wildner 
18512bd3c8bSSascha Wildner static void mos_setmulti(struct usb_ether *);
18612bd3c8bSSascha Wildner static void mos_setpromisc(struct usb_ether *);
18712bd3c8bSSascha Wildner 
18812bd3c8bSSascha Wildner static const struct usb_config mos_config[MOS_ENDPT_MAX] = {
18912bd3c8bSSascha Wildner 
19012bd3c8bSSascha Wildner 	[MOS_ENDPT_TX] = {
19112bd3c8bSSascha Wildner 		.type = UE_BULK,
19212bd3c8bSSascha Wildner 		.endpoint = UE_ADDR_ANY,
19312bd3c8bSSascha Wildner 		.direction = UE_DIR_OUT,
19412bd3c8bSSascha Wildner 		.bufsize = (MCLBYTES + 2),
19512bd3c8bSSascha Wildner 		.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
19612bd3c8bSSascha Wildner 		.callback = mos_bulk_write_callback,
19712bd3c8bSSascha Wildner 		.timeout = 10000,
19812bd3c8bSSascha Wildner 	},
19912bd3c8bSSascha Wildner 
20012bd3c8bSSascha Wildner 	[MOS_ENDPT_RX] = {
20112bd3c8bSSascha Wildner 		.type = UE_BULK,
20212bd3c8bSSascha Wildner 		.endpoint = UE_ADDR_ANY,
20312bd3c8bSSascha Wildner 		.direction = UE_DIR_IN,
20412bd3c8bSSascha Wildner 		.bufsize = (MCLBYTES + 4 + ETHER_CRC_LEN),
20512bd3c8bSSascha Wildner 		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
20612bd3c8bSSascha Wildner 		.callback = mos_bulk_read_callback,
20712bd3c8bSSascha Wildner 	},
20812bd3c8bSSascha Wildner 
20912bd3c8bSSascha Wildner 	[MOS_ENDPT_INTR] = {
21012bd3c8bSSascha Wildner 		.type = UE_INTERRUPT,
21112bd3c8bSSascha Wildner 		.endpoint = UE_ADDR_ANY,
21212bd3c8bSSascha Wildner 		.direction = UE_DIR_IN,
21312bd3c8bSSascha Wildner 		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
21412bd3c8bSSascha Wildner 		.bufsize = 0,
21512bd3c8bSSascha Wildner 		.callback = mos_intr_callback,
21612bd3c8bSSascha Wildner 	},
21712bd3c8bSSascha Wildner };
21812bd3c8bSSascha Wildner 
21912bd3c8bSSascha Wildner static device_method_t mos_methods[] = {
22012bd3c8bSSascha Wildner 	/* Device interface */
22112bd3c8bSSascha Wildner 	DEVMETHOD(device_probe, mos_probe),
22212bd3c8bSSascha Wildner 	DEVMETHOD(device_attach, mos_attach),
22312bd3c8bSSascha Wildner 	DEVMETHOD(device_detach, mos_detach),
22412bd3c8bSSascha Wildner 
22512bd3c8bSSascha Wildner 	/* MII interface */
22612bd3c8bSSascha Wildner 	DEVMETHOD(miibus_readreg, mos_miibus_readreg),
22712bd3c8bSSascha Wildner 	DEVMETHOD(miibus_writereg, mos_miibus_writereg),
22812bd3c8bSSascha Wildner 	DEVMETHOD(miibus_statchg, mos_miibus_statchg),
22912bd3c8bSSascha Wildner 
23012bd3c8bSSascha Wildner 	DEVMETHOD_END
23112bd3c8bSSascha Wildner };
23212bd3c8bSSascha Wildner 
23312bd3c8bSSascha Wildner static driver_t mos_driver = {
23412bd3c8bSSascha Wildner 	.name = "mos",
23512bd3c8bSSascha Wildner 	.methods = mos_methods,
23612bd3c8bSSascha Wildner 	.size = sizeof(struct mos_softc)
23712bd3c8bSSascha Wildner };
23812bd3c8bSSascha Wildner 
23912bd3c8bSSascha Wildner static devclass_t mos_devclass;
24012bd3c8bSSascha Wildner 
2413a25be87SSascha Wildner DRIVER_MODULE(mos, uhub, mos_driver, mos_devclass, NULL, NULL);
2423a25be87SSascha Wildner DRIVER_MODULE(miibus, mos, miibus_driver, miibus_devclass, NULL, NULL);
24312bd3c8bSSascha Wildner MODULE_DEPEND(mos, uether, 1, 1, 1);
24412bd3c8bSSascha Wildner MODULE_DEPEND(mos, usb, 1, 1, 1);
24512bd3c8bSSascha Wildner MODULE_DEPEND(mos, ether, 1, 1, 1);
24612bd3c8bSSascha Wildner MODULE_DEPEND(mos, miibus, 1, 1, 1);
24712bd3c8bSSascha Wildner 
24812bd3c8bSSascha Wildner static const struct usb_ether_methods mos_ue_methods = {
24912bd3c8bSSascha Wildner 	.ue_attach_post = mos_attach_post,
25012bd3c8bSSascha Wildner 	.ue_start = mos_start,
25112bd3c8bSSascha Wildner 	.ue_init = mos_init,
25212bd3c8bSSascha Wildner 	.ue_stop = mos_stop,
25312bd3c8bSSascha Wildner 	.ue_tick = mos_tick,
25412bd3c8bSSascha Wildner 	.ue_setmulti = mos_setmulti,
25512bd3c8bSSascha Wildner 	.ue_setpromisc = mos_setpromisc,
25612bd3c8bSSascha Wildner 	.ue_mii_upd = mos_ifmedia_upd,
25712bd3c8bSSascha Wildner 	.ue_mii_sts = mos_ifmedia_sts,
25812bd3c8bSSascha Wildner };
25912bd3c8bSSascha Wildner 
26012bd3c8bSSascha Wildner 
26112bd3c8bSSascha Wildner static int
mos_reg_read_1(struct mos_softc * sc,int reg)26212bd3c8bSSascha Wildner mos_reg_read_1(struct mos_softc *sc, int reg)
26312bd3c8bSSascha Wildner {
26412bd3c8bSSascha Wildner 	struct usb_device_request req;
26512bd3c8bSSascha Wildner 	usb_error_t err;
26612bd3c8bSSascha Wildner 	uByte val = 0;
26712bd3c8bSSascha Wildner 
26812bd3c8bSSascha Wildner 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
26912bd3c8bSSascha Wildner 	req.bRequest = MOS_UR_READREG;
27012bd3c8bSSascha Wildner 	USETW(req.wValue, 0);
27112bd3c8bSSascha Wildner 	USETW(req.wIndex, reg);
27212bd3c8bSSascha Wildner 	USETW(req.wLength, 1);
27312bd3c8bSSascha Wildner 
27412bd3c8bSSascha Wildner 	err = uether_do_request(&sc->sc_ue, &req, &val, 1000);
27512bd3c8bSSascha Wildner 
27612bd3c8bSSascha Wildner 	if (err) {
27712bd3c8bSSascha Wildner 		MOS_DPRINTFN("mos_reg_read_1 error, reg: %d\n", reg);
27812bd3c8bSSascha Wildner 		return (-1);
27912bd3c8bSSascha Wildner 	}
28012bd3c8bSSascha Wildner 	return (val);
28112bd3c8bSSascha Wildner }
28212bd3c8bSSascha Wildner 
28312bd3c8bSSascha Wildner static int
mos_reg_read_2(struct mos_softc * sc,int reg)28412bd3c8bSSascha Wildner mos_reg_read_2(struct mos_softc *sc, int reg)
28512bd3c8bSSascha Wildner {
28612bd3c8bSSascha Wildner 	struct usb_device_request req;
28712bd3c8bSSascha Wildner 	usb_error_t err;
28812bd3c8bSSascha Wildner 	uWord val;
28912bd3c8bSSascha Wildner 
29012bd3c8bSSascha Wildner 	USETW(val, 0);
29112bd3c8bSSascha Wildner 
29212bd3c8bSSascha Wildner 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
29312bd3c8bSSascha Wildner 	req.bRequest = MOS_UR_READREG;
29412bd3c8bSSascha Wildner 	USETW(req.wValue, 0);
29512bd3c8bSSascha Wildner 	USETW(req.wIndex, reg);
29612bd3c8bSSascha Wildner 	USETW(req.wLength, 2);
29712bd3c8bSSascha Wildner 
29812bd3c8bSSascha Wildner 	err = uether_do_request(&sc->sc_ue, &req, &val, 1000);
29912bd3c8bSSascha Wildner 
30012bd3c8bSSascha Wildner 	if (err) {
30112bd3c8bSSascha Wildner 		MOS_DPRINTFN("mos_reg_read_2 error, reg: %d", reg);
30212bd3c8bSSascha Wildner 		return (-1);
30312bd3c8bSSascha Wildner 	}
30412bd3c8bSSascha Wildner 	return (UGETW(val));
30512bd3c8bSSascha Wildner }
30612bd3c8bSSascha Wildner 
30712bd3c8bSSascha Wildner static int
mos_reg_write_1(struct mos_softc * sc,int reg,int aval)30812bd3c8bSSascha Wildner mos_reg_write_1(struct mos_softc *sc, int reg, int aval)
30912bd3c8bSSascha Wildner {
31012bd3c8bSSascha Wildner 	struct usb_device_request req;
31112bd3c8bSSascha Wildner 	usb_error_t err;
31212bd3c8bSSascha Wildner 	uByte val;
31312bd3c8bSSascha Wildner 	val = aval;
31412bd3c8bSSascha Wildner 
31512bd3c8bSSascha Wildner 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
31612bd3c8bSSascha Wildner 	req.bRequest = MOS_UR_WRITEREG;
31712bd3c8bSSascha Wildner 	USETW(req.wValue, 0);
31812bd3c8bSSascha Wildner 	USETW(req.wIndex, reg);
31912bd3c8bSSascha Wildner 	USETW(req.wLength, 1);
32012bd3c8bSSascha Wildner 
32112bd3c8bSSascha Wildner 	err = uether_do_request(&sc->sc_ue, &req, &val, 1000);
32212bd3c8bSSascha Wildner 
32312bd3c8bSSascha Wildner 	if (err) {
32412bd3c8bSSascha Wildner 		MOS_DPRINTFN("mos_reg_write_1 error, reg: %d", reg);
32512bd3c8bSSascha Wildner 		return (-1);
32612bd3c8bSSascha Wildner 	}
32712bd3c8bSSascha Wildner 	return (0);
32812bd3c8bSSascha Wildner }
32912bd3c8bSSascha Wildner 
33012bd3c8bSSascha Wildner static int
mos_reg_write_2(struct mos_softc * sc,int reg,int aval)33112bd3c8bSSascha Wildner mos_reg_write_2(struct mos_softc *sc, int reg, int aval)
33212bd3c8bSSascha Wildner {
33312bd3c8bSSascha Wildner 	struct usb_device_request req;
33412bd3c8bSSascha Wildner 	usb_error_t err;
33512bd3c8bSSascha Wildner 	uWord val;
33612bd3c8bSSascha Wildner 
33712bd3c8bSSascha Wildner 	USETW(val, aval);
33812bd3c8bSSascha Wildner 
33912bd3c8bSSascha Wildner 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
34012bd3c8bSSascha Wildner 	req.bRequest = MOS_UR_WRITEREG;
34112bd3c8bSSascha Wildner 	USETW(req.wValue, 0);
34212bd3c8bSSascha Wildner 	USETW(req.wIndex, reg);
34312bd3c8bSSascha Wildner 	USETW(req.wLength, 2);
34412bd3c8bSSascha Wildner 
34512bd3c8bSSascha Wildner 	err = uether_do_request(&sc->sc_ue, &req, &val, 1000);
34612bd3c8bSSascha Wildner 
34712bd3c8bSSascha Wildner 	if (err) {
34812bd3c8bSSascha Wildner 		MOS_DPRINTFN("mos_reg_write_2 error, reg: %d", reg);
34912bd3c8bSSascha Wildner 		return (-1);
35012bd3c8bSSascha Wildner 	}
35112bd3c8bSSascha Wildner 	return (0);
35212bd3c8bSSascha Wildner }
35312bd3c8bSSascha Wildner 
35412bd3c8bSSascha Wildner static int
mos_readmac(struct mos_softc * sc,u_char * mac)35512bd3c8bSSascha Wildner mos_readmac(struct mos_softc *sc, u_char *mac)
35612bd3c8bSSascha Wildner {
35712bd3c8bSSascha Wildner 	struct usb_device_request req;
35812bd3c8bSSascha Wildner 	usb_error_t err;
35912bd3c8bSSascha Wildner 
36012bd3c8bSSascha Wildner 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
36112bd3c8bSSascha Wildner 	req.bRequest = MOS_UR_READREG;
36212bd3c8bSSascha Wildner 	USETW(req.wValue, 0);
36312bd3c8bSSascha Wildner 	USETW(req.wIndex, MOS_MAC);
36412bd3c8bSSascha Wildner 	USETW(req.wLength, ETHER_ADDR_LEN);
36512bd3c8bSSascha Wildner 
36612bd3c8bSSascha Wildner 	err = uether_do_request(&sc->sc_ue, &req, mac, 1000);
36712bd3c8bSSascha Wildner 
36812bd3c8bSSascha Wildner 	if (err) {
36912bd3c8bSSascha Wildner 		return (-1);
37012bd3c8bSSascha Wildner 	}
37112bd3c8bSSascha Wildner 	return (0);
37212bd3c8bSSascha Wildner }
37312bd3c8bSSascha Wildner 
37412bd3c8bSSascha Wildner static int
mos_writemac(struct mos_softc * sc,uint8_t * mac)37512bd3c8bSSascha Wildner mos_writemac(struct mos_softc *sc, uint8_t *mac)
37612bd3c8bSSascha Wildner {
37712bd3c8bSSascha Wildner 	struct usb_device_request req;
37812bd3c8bSSascha Wildner 	usb_error_t err;
37912bd3c8bSSascha Wildner 
38012bd3c8bSSascha Wildner 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
38112bd3c8bSSascha Wildner 	req.bRequest = MOS_UR_WRITEREG;
38212bd3c8bSSascha Wildner 	USETW(req.wValue, 0);
38312bd3c8bSSascha Wildner 	USETW(req.wIndex, MOS_MAC);
38412bd3c8bSSascha Wildner 	USETW(req.wLength, ETHER_ADDR_LEN);
38512bd3c8bSSascha Wildner 
38612bd3c8bSSascha Wildner 	err = uether_do_request(&sc->sc_ue, &req, mac, 1000);
38712bd3c8bSSascha Wildner 
38812bd3c8bSSascha Wildner 	if (err) {
38912bd3c8bSSascha Wildner 		MOS_DPRINTFN("mos_writemac error");
39012bd3c8bSSascha Wildner 		return (-1);
39112bd3c8bSSascha Wildner 	}
39212bd3c8bSSascha Wildner 	return (0);
39312bd3c8bSSascha Wildner }
39412bd3c8bSSascha Wildner 
39512bd3c8bSSascha Wildner static int
mos_write_mcast(struct mos_softc * sc,u_char * hashtbl)39612bd3c8bSSascha Wildner mos_write_mcast(struct mos_softc *sc, u_char *hashtbl)
39712bd3c8bSSascha Wildner {
39812bd3c8bSSascha Wildner 	struct usb_device_request req;
39912bd3c8bSSascha Wildner 	usb_error_t err;
40012bd3c8bSSascha Wildner 
40112bd3c8bSSascha Wildner 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
40212bd3c8bSSascha Wildner 	req.bRequest = MOS_UR_WRITEREG;
40312bd3c8bSSascha Wildner 	USETW(req.wValue, 0);
40412bd3c8bSSascha Wildner 	USETW(req.wIndex, MOS_MCAST_TABLE);
40512bd3c8bSSascha Wildner 	USETW(req.wLength, 8);
40612bd3c8bSSascha Wildner 
40712bd3c8bSSascha Wildner 	err = uether_do_request(&sc->sc_ue, &req, hashtbl, 1000);
40812bd3c8bSSascha Wildner 
40912bd3c8bSSascha Wildner 	if (err) {
41012bd3c8bSSascha Wildner 		MOS_DPRINTFN("mos_reg_mcast error");
41112bd3c8bSSascha Wildner 		return (-1);
41212bd3c8bSSascha Wildner 	}
41312bd3c8bSSascha Wildner 	return (0);
41412bd3c8bSSascha Wildner }
41512bd3c8bSSascha Wildner 
41612bd3c8bSSascha Wildner static int
mos_miibus_readreg(device_t dev,int phy,int reg)4175d302545SFrançois Tigeot mos_miibus_readreg(device_t dev, int phy, int reg)
41812bd3c8bSSascha Wildner {
41912bd3c8bSSascha Wildner 	struct mos_softc *sc = device_get_softc(dev);
42012bd3c8bSSascha Wildner 	uWord val;
42112bd3c8bSSascha Wildner 	int i, res, locked;
42212bd3c8bSSascha Wildner 
42312bd3c8bSSascha Wildner 	USETW(val, 0);
42412bd3c8bSSascha Wildner 
425559d4eaeSSascha Wildner 	locked = lockowned(&sc->sc_lock);
42612bd3c8bSSascha Wildner 	if (!locked)
42712bd3c8bSSascha Wildner 		MOS_LOCK(sc);
42812bd3c8bSSascha Wildner 
42912bd3c8bSSascha Wildner 	mos_reg_write_2(sc, MOS_PHY_DATA, 0);
43012bd3c8bSSascha Wildner 	mos_reg_write_1(sc, MOS_PHY_CTL, (phy & MOS_PHYCTL_PHYADDR) |
43112bd3c8bSSascha Wildner 	    MOS_PHYCTL_READ);
43212bd3c8bSSascha Wildner 	mos_reg_write_1(sc, MOS_PHY_STS, (reg & MOS_PHYSTS_PHYREG) |
43312bd3c8bSSascha Wildner 	    MOS_PHYSTS_PENDING);
43412bd3c8bSSascha Wildner 
43512bd3c8bSSascha Wildner 	for (i = 0; i < MOS_TIMEOUT; i++) {
43612bd3c8bSSascha Wildner 		if (mos_reg_read_1(sc, MOS_PHY_STS) & MOS_PHYSTS_READY)
43712bd3c8bSSascha Wildner 			break;
43812bd3c8bSSascha Wildner 	}
43912bd3c8bSSascha Wildner 	if (i == MOS_TIMEOUT) {
44012bd3c8bSSascha Wildner 		MOS_DPRINTFN("MII read timeout");
44112bd3c8bSSascha Wildner 	}
44212bd3c8bSSascha Wildner 	res = mos_reg_read_2(sc, MOS_PHY_DATA);
44312bd3c8bSSascha Wildner 
44412bd3c8bSSascha Wildner 	if (!locked)
44512bd3c8bSSascha Wildner 		MOS_UNLOCK(sc);
44612bd3c8bSSascha Wildner 	return (res);
44712bd3c8bSSascha Wildner }
44812bd3c8bSSascha Wildner 
44912bd3c8bSSascha Wildner static int
mos_miibus_writereg(device_t dev,int phy,int reg,int val)45012bd3c8bSSascha Wildner mos_miibus_writereg(device_t dev, int phy, int reg, int val)
45112bd3c8bSSascha Wildner {
45212bd3c8bSSascha Wildner 	struct mos_softc *sc = device_get_softc(dev);
45312bd3c8bSSascha Wildner 	int i, locked;
45412bd3c8bSSascha Wildner 
455559d4eaeSSascha Wildner 	locked = lockowned(&sc->sc_lock);
45612bd3c8bSSascha Wildner 	if (!locked)
45712bd3c8bSSascha Wildner 		MOS_LOCK(sc);
45812bd3c8bSSascha Wildner 
45912bd3c8bSSascha Wildner 	mos_reg_write_2(sc, MOS_PHY_DATA, val);
46012bd3c8bSSascha Wildner 	mos_reg_write_1(sc, MOS_PHY_CTL, (phy & MOS_PHYCTL_PHYADDR) |
46112bd3c8bSSascha Wildner 	    MOS_PHYCTL_WRITE);
46212bd3c8bSSascha Wildner 	mos_reg_write_1(sc, MOS_PHY_STS, (reg & MOS_PHYSTS_PHYREG) |
46312bd3c8bSSascha Wildner 	    MOS_PHYSTS_PENDING);
46412bd3c8bSSascha Wildner 
46512bd3c8bSSascha Wildner 	for (i = 0; i < MOS_TIMEOUT; i++) {
46612bd3c8bSSascha Wildner 		if (mos_reg_read_1(sc, MOS_PHY_STS) & MOS_PHYSTS_READY)
46712bd3c8bSSascha Wildner 			break;
46812bd3c8bSSascha Wildner 	}
46912bd3c8bSSascha Wildner 	if (i == MOS_TIMEOUT)
47012bd3c8bSSascha Wildner 		MOS_DPRINTFN("MII write timeout");
47112bd3c8bSSascha Wildner 
47212bd3c8bSSascha Wildner 	if (!locked)
47312bd3c8bSSascha Wildner 		MOS_UNLOCK(sc);
47412bd3c8bSSascha Wildner 	return 0;
47512bd3c8bSSascha Wildner }
47612bd3c8bSSascha Wildner 
47712bd3c8bSSascha Wildner static void
mos_miibus_statchg(device_t dev)47812bd3c8bSSascha Wildner mos_miibus_statchg(device_t dev)
47912bd3c8bSSascha Wildner {
48012bd3c8bSSascha Wildner 	struct mos_softc *sc = device_get_softc(dev);
48112bd3c8bSSascha Wildner 	struct mii_data *mii = GET_MII(sc);
48212bd3c8bSSascha Wildner 	int val, err, locked;
48312bd3c8bSSascha Wildner 
484559d4eaeSSascha Wildner 	locked = lockowned(&sc->sc_lock);
48512bd3c8bSSascha Wildner 	if (!locked)
48612bd3c8bSSascha Wildner 		MOS_LOCK(sc);
48712bd3c8bSSascha Wildner 
48812bd3c8bSSascha Wildner 	/* disable RX, TX prior to changing FDX, SPEEDSEL */
48912bd3c8bSSascha Wildner 	val = mos_reg_read_1(sc, MOS_CTL);
49012bd3c8bSSascha Wildner 	val &= ~(MOS_CTL_TX_ENB | MOS_CTL_RX_ENB);
49112bd3c8bSSascha Wildner 	mos_reg_write_1(sc, MOS_CTL, val);
49212bd3c8bSSascha Wildner 
49312bd3c8bSSascha Wildner 	/* reset register which counts dropped frames */
49412bd3c8bSSascha Wildner 	mos_reg_write_1(sc, MOS_FRAME_DROP_CNT, 0);
49512bd3c8bSSascha Wildner 
49612bd3c8bSSascha Wildner 	if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX)
49712bd3c8bSSascha Wildner 		val |= MOS_CTL_FDX_ENB;
49812bd3c8bSSascha Wildner 	else
49912bd3c8bSSascha Wildner 		val &= ~(MOS_CTL_FDX_ENB);
50012bd3c8bSSascha Wildner 
50112bd3c8bSSascha Wildner 	switch (IFM_SUBTYPE(mii->mii_media_active)) {
50212bd3c8bSSascha Wildner 	case IFM_100_TX:
50312bd3c8bSSascha Wildner 		val |= MOS_CTL_SPEEDSEL;
50412bd3c8bSSascha Wildner 		break;
50512bd3c8bSSascha Wildner 	case IFM_10_T:
50612bd3c8bSSascha Wildner 		val &= ~(MOS_CTL_SPEEDSEL);
50712bd3c8bSSascha Wildner 		break;
50812bd3c8bSSascha Wildner 	}
50912bd3c8bSSascha Wildner 
51012bd3c8bSSascha Wildner 	/* re-enable TX, RX */
51112bd3c8bSSascha Wildner 	val |= (MOS_CTL_TX_ENB | MOS_CTL_RX_ENB);
51212bd3c8bSSascha Wildner 	err = mos_reg_write_1(sc, MOS_CTL, val);
51312bd3c8bSSascha Wildner 
51412bd3c8bSSascha Wildner 	if (err)
51512bd3c8bSSascha Wildner 		MOS_DPRINTFN("media change failed");
51612bd3c8bSSascha Wildner 
51712bd3c8bSSascha Wildner 	if (!locked)
51812bd3c8bSSascha Wildner 		MOS_UNLOCK(sc);
51912bd3c8bSSascha Wildner }
52012bd3c8bSSascha Wildner 
52112bd3c8bSSascha Wildner /*
52212bd3c8bSSascha Wildner  * Set media options.
52312bd3c8bSSascha Wildner  */
52412bd3c8bSSascha Wildner static int
mos_ifmedia_upd(struct ifnet * ifp)52512bd3c8bSSascha Wildner mos_ifmedia_upd(struct ifnet *ifp)
52612bd3c8bSSascha Wildner {
52712bd3c8bSSascha Wildner 	struct mos_softc *sc = ifp->if_softc;
52812bd3c8bSSascha Wildner 	struct mii_data *mii = GET_MII(sc);
52912bd3c8bSSascha Wildner 	struct mii_softc *miisc;
530f8577199SSascha Wildner 	int error;
53112bd3c8bSSascha Wildner 
532559d4eaeSSascha Wildner 	MOS_LOCK_ASSERT(sc);
53312bd3c8bSSascha Wildner 
53412bd3c8bSSascha Wildner 	sc->mos_link = 0;
53512bd3c8bSSascha Wildner 	if (mii->mii_instance) {
53612bd3c8bSSascha Wildner 		LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
53712bd3c8bSSascha Wildner 		    mii_phy_reset(miisc);
53812bd3c8bSSascha Wildner 	}
539f8577199SSascha Wildner 	error = mii_mediachg(mii);
540f8577199SSascha Wildner 	return (error);
54112bd3c8bSSascha Wildner }
54212bd3c8bSSascha Wildner 
54312bd3c8bSSascha Wildner /*
54412bd3c8bSSascha Wildner  * Report current media status.
54512bd3c8bSSascha Wildner  */
54612bd3c8bSSascha Wildner static void
mos_ifmedia_sts(struct ifnet * ifp,struct ifmediareq * ifmr)54712bd3c8bSSascha Wildner mos_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
54812bd3c8bSSascha Wildner {
54912bd3c8bSSascha Wildner 	struct mos_softc *sc = ifp->if_softc;
55012bd3c8bSSascha Wildner 	struct mii_data *mii = GET_MII(sc);
55112bd3c8bSSascha Wildner 
55212bd3c8bSSascha Wildner 	MOS_LOCK(sc);
55312bd3c8bSSascha Wildner 	mii_pollstat(mii);
55412bd3c8bSSascha Wildner 
55512bd3c8bSSascha Wildner 	ifmr->ifm_active = mii->mii_media_active;
55612bd3c8bSSascha Wildner 	ifmr->ifm_status = mii->mii_media_status;
55712bd3c8bSSascha Wildner 	MOS_UNLOCK(sc);
55812bd3c8bSSascha Wildner }
55912bd3c8bSSascha Wildner 
56012bd3c8bSSascha Wildner static void
mos_setpromisc(struct usb_ether * ue)56112bd3c8bSSascha Wildner mos_setpromisc(struct usb_ether *ue)
56212bd3c8bSSascha Wildner {
56312bd3c8bSSascha Wildner 	struct mos_softc *sc = uether_getsc(ue);
56412bd3c8bSSascha Wildner 	struct ifnet *ifp = uether_getifp(ue);
56512bd3c8bSSascha Wildner 
56612bd3c8bSSascha Wildner 	uint8_t rxmode;
56712bd3c8bSSascha Wildner 
568559d4eaeSSascha Wildner 	MOS_LOCK_ASSERT(sc);
56912bd3c8bSSascha Wildner 
57012bd3c8bSSascha Wildner 	rxmode = mos_reg_read_1(sc, MOS_CTL);
57112bd3c8bSSascha Wildner 
57212bd3c8bSSascha Wildner 	/* If we want promiscuous mode, set the allframes bit. */
57312bd3c8bSSascha Wildner 	if (ifp->if_flags & IFF_PROMISC) {
57412bd3c8bSSascha Wildner 		rxmode |= MOS_CTL_RX_PROMISC;
57512bd3c8bSSascha Wildner 	} else {
57612bd3c8bSSascha Wildner 		rxmode &= ~MOS_CTL_RX_PROMISC;
57712bd3c8bSSascha Wildner 	}
57812bd3c8bSSascha Wildner 
57912bd3c8bSSascha Wildner 	mos_reg_write_1(sc, MOS_CTL, rxmode);
58012bd3c8bSSascha Wildner }
58112bd3c8bSSascha Wildner 
58212bd3c8bSSascha Wildner 
58312bd3c8bSSascha Wildner 
58412bd3c8bSSascha Wildner static void
mos_setmulti(struct usb_ether * ue)58512bd3c8bSSascha Wildner mos_setmulti(struct usb_ether *ue)
58612bd3c8bSSascha Wildner {
58712bd3c8bSSascha Wildner 	struct mos_softc *sc = uether_getsc(ue);
58812bd3c8bSSascha Wildner 	struct ifnet *ifp = uether_getifp(ue);
58912bd3c8bSSascha Wildner 	struct ifmultiaddr *ifma;
59012bd3c8bSSascha Wildner 
59112bd3c8bSSascha Wildner 	uint32_t h = 0;
59212bd3c8bSSascha Wildner 	uint8_t rxmode;
59312bd3c8bSSascha Wildner 	uint8_t hashtbl[8] = {0, 0, 0, 0, 0, 0, 0, 0};
59412bd3c8bSSascha Wildner 	int allmulti = 0;
59512bd3c8bSSascha Wildner 
596559d4eaeSSascha Wildner 	MOS_LOCK_ASSERT(sc);
59712bd3c8bSSascha Wildner 
59812bd3c8bSSascha Wildner 	rxmode = mos_reg_read_1(sc, MOS_CTL);
59912bd3c8bSSascha Wildner 
60012bd3c8bSSascha Wildner 	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC)
60112bd3c8bSSascha Wildner 		allmulti = 1;
60212bd3c8bSSascha Wildner 
60312bd3c8bSSascha Wildner 	/* get all new ones */
60412bd3c8bSSascha Wildner 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
60512bd3c8bSSascha Wildner 		if (ifma->ifma_addr->sa_family != AF_LINK) {
60612bd3c8bSSascha Wildner 			allmulti = 1;
60712bd3c8bSSascha Wildner 			continue;
6080fdb7d01SSascha Wildner 		}
60912bd3c8bSSascha Wildner 		h = ether_crc32_be(LLADDR((struct sockaddr_dl *)
61012bd3c8bSSascha Wildner 		    ifma->ifma_addr), ETHER_ADDR_LEN) >> 26;
611691f0a75SSascha Wildner 		setbit(hashtbl, h);
61212bd3c8bSSascha Wildner 	}
61312bd3c8bSSascha Wildner 
61412bd3c8bSSascha Wildner 	/* now program new ones */
61512bd3c8bSSascha Wildner 	if (allmulti == 1) {
61612bd3c8bSSascha Wildner 		rxmode |= MOS_CTL_ALLMULTI;
61712bd3c8bSSascha Wildner 		mos_reg_write_1(sc, MOS_CTL, rxmode);
61812bd3c8bSSascha Wildner 	} else {
61912bd3c8bSSascha Wildner 		rxmode &= ~MOS_CTL_ALLMULTI;
62012bd3c8bSSascha Wildner 		mos_write_mcast(sc, (void *)&hashtbl);
62112bd3c8bSSascha Wildner 		mos_reg_write_1(sc, MOS_CTL, rxmode);
62212bd3c8bSSascha Wildner 	}
62312bd3c8bSSascha Wildner }
62412bd3c8bSSascha Wildner 
62512bd3c8bSSascha Wildner static void
mos_reset(struct mos_softc * sc)62612bd3c8bSSascha Wildner mos_reset(struct mos_softc *sc)
62712bd3c8bSSascha Wildner {
62812bd3c8bSSascha Wildner 	uint8_t ctl;
62912bd3c8bSSascha Wildner 
63012bd3c8bSSascha Wildner 	ctl = mos_reg_read_1(sc, MOS_CTL);
63112bd3c8bSSascha Wildner 	ctl &= ~(MOS_CTL_RX_PROMISC | MOS_CTL_ALLMULTI | MOS_CTL_TX_ENB |
63212bd3c8bSSascha Wildner 	    MOS_CTL_RX_ENB);
63312bd3c8bSSascha Wildner 	/* Disable RX, TX, promiscuous and allmulticast mode */
63412bd3c8bSSascha Wildner 	mos_reg_write_1(sc, MOS_CTL, ctl);
63512bd3c8bSSascha Wildner 
63612bd3c8bSSascha Wildner 	/* Reset frame drop counter register to zero */
63712bd3c8bSSascha Wildner 	mos_reg_write_1(sc, MOS_FRAME_DROP_CNT, 0);
63812bd3c8bSSascha Wildner 
63912bd3c8bSSascha Wildner 	/* Wait a little while for the chip to get its brains in order. */
640559d4eaeSSascha Wildner 	usb_pause_mtx(&sc->sc_lock, hz / 128);
64112bd3c8bSSascha Wildner 	return;
64212bd3c8bSSascha Wildner }
64312bd3c8bSSascha Wildner 
64412bd3c8bSSascha Wildner static void
mos_chip_init(struct mos_softc * sc)64512bd3c8bSSascha Wildner mos_chip_init(struct mos_softc *sc)
64612bd3c8bSSascha Wildner {
64712bd3c8bSSascha Wildner 	int i;
64812bd3c8bSSascha Wildner 
64912bd3c8bSSascha Wildner 	/*
65012bd3c8bSSascha Wildner 	 * Rev.C devices have a pause threshold register which needs to be set
65112bd3c8bSSascha Wildner 	 * at startup.
65212bd3c8bSSascha Wildner 	 */
65312bd3c8bSSascha Wildner 	if (mos_reg_read_1(sc, MOS_PAUSE_TRHD) != -1) {
65412bd3c8bSSascha Wildner 		for (i = 0; i < MOS_PAUSE_REWRITES; i++)
65512bd3c8bSSascha Wildner 			mos_reg_write_1(sc, MOS_PAUSE_TRHD, 0);
65612bd3c8bSSascha Wildner 	}
65712bd3c8bSSascha Wildner 	sc->mos_phyaddrs[0] = 1;
65812bd3c8bSSascha Wildner 	sc->mos_phyaddrs[1] = 0xFF;
65912bd3c8bSSascha Wildner }
66012bd3c8bSSascha Wildner 
66112bd3c8bSSascha Wildner /*
66212bd3c8bSSascha Wildner  * Probe for a MCS7x30 chip.
66312bd3c8bSSascha Wildner  */
66412bd3c8bSSascha Wildner static int
mos_probe(device_t dev)66512bd3c8bSSascha Wildner mos_probe(device_t dev)
66612bd3c8bSSascha Wildner {
66712bd3c8bSSascha Wildner 	struct usb_attach_arg *uaa = device_get_ivars(dev);
66812bd3c8bSSascha Wildner         int retval;
66912bd3c8bSSascha Wildner 
67012bd3c8bSSascha Wildner 	if (uaa->usb_mode != USB_MODE_HOST)
67112bd3c8bSSascha Wildner 		return (ENXIO);
67212bd3c8bSSascha Wildner 	if (uaa->info.bConfigIndex != MOS_CONFIG_IDX)
67312bd3c8bSSascha Wildner 		return (ENXIO);
67412bd3c8bSSascha Wildner 	if (uaa->info.bIfaceIndex != MOS_IFACE_IDX)
67512bd3c8bSSascha Wildner 		return (ENXIO);
67612bd3c8bSSascha Wildner 
67712bd3c8bSSascha Wildner 	retval = usbd_lookup_id_by_uaa(mos_devs, sizeof(mos_devs), uaa);
67812bd3c8bSSascha Wildner 	return (retval);
67912bd3c8bSSascha Wildner }
68012bd3c8bSSascha Wildner 
68112bd3c8bSSascha Wildner /*
68212bd3c8bSSascha Wildner  * Attach the interface. Allocate softc structures, do ifmedia
68312bd3c8bSSascha Wildner  * setup and ethernet/BPF attach.
68412bd3c8bSSascha Wildner  */
68512bd3c8bSSascha Wildner static int
mos_attach(device_t dev)68612bd3c8bSSascha Wildner mos_attach(device_t dev)
68712bd3c8bSSascha Wildner {
68812bd3c8bSSascha Wildner 	struct usb_attach_arg *uaa = device_get_ivars(dev);
68912bd3c8bSSascha Wildner 	struct mos_softc *sc = device_get_softc(dev);
69012bd3c8bSSascha Wildner 	struct usb_ether *ue = &sc->sc_ue;
69112bd3c8bSSascha Wildner 	uint8_t iface_index;
69212bd3c8bSSascha Wildner 	int error;
69312bd3c8bSSascha Wildner 
69412bd3c8bSSascha Wildner 	sc->mos_flags = USB_GET_DRIVER_INFO(uaa);
69512bd3c8bSSascha Wildner 
69612bd3c8bSSascha Wildner 	device_set_usb_desc(dev);
697559d4eaeSSascha Wildner 	lockinit(&sc->sc_lock, device_get_nameunit(dev), 0, LK_CANRECURSE);
69812bd3c8bSSascha Wildner 
69912bd3c8bSSascha Wildner 	iface_index = MOS_IFACE_IDX;
70012bd3c8bSSascha Wildner 	error = usbd_transfer_setup(uaa->device, &iface_index,
70112bd3c8bSSascha Wildner 	    sc->sc_xfer, mos_config, MOS_ENDPT_MAX,
702559d4eaeSSascha Wildner 	    sc, &sc->sc_lock);
70312bd3c8bSSascha Wildner 
70412bd3c8bSSascha Wildner 	if (error) {
70512bd3c8bSSascha Wildner 		device_printf(dev, "allocating USB transfers failed\n");
70612bd3c8bSSascha Wildner 		goto detach;
70712bd3c8bSSascha Wildner 	}
70812bd3c8bSSascha Wildner 	ue->ue_sc = sc;
70912bd3c8bSSascha Wildner 	ue->ue_dev = dev;
71012bd3c8bSSascha Wildner 	ue->ue_udev = uaa->device;
711559d4eaeSSascha Wildner 	ue->ue_lock = &sc->sc_lock;
71212bd3c8bSSascha Wildner 	ue->ue_methods = &mos_ue_methods;
71312bd3c8bSSascha Wildner 
71412bd3c8bSSascha Wildner 
71512bd3c8bSSascha Wildner 	if (sc->mos_flags & MCS7730) {
71612bd3c8bSSascha Wildner 		MOS_DPRINTFN("model: MCS7730");
71712bd3c8bSSascha Wildner 	} else if (sc->mos_flags & MCS7830) {
71812bd3c8bSSascha Wildner 		MOS_DPRINTFN("model: MCS7830");
719f8577199SSascha Wildner 	} else if (sc->mos_flags & MCS7832) {
720f8577199SSascha Wildner 		MOS_DPRINTFN("model: MCS7832");
72112bd3c8bSSascha Wildner 	}
72212bd3c8bSSascha Wildner 	error = uether_ifattach(ue);
72312bd3c8bSSascha Wildner 	if (error) {
72412bd3c8bSSascha Wildner 		device_printf(dev, "could not attach interface\n");
72512bd3c8bSSascha Wildner 		goto detach;
72612bd3c8bSSascha Wildner 	}
72712bd3c8bSSascha Wildner 	return (0);
72812bd3c8bSSascha Wildner 
72912bd3c8bSSascha Wildner 
73012bd3c8bSSascha Wildner detach:
73112bd3c8bSSascha Wildner 	mos_detach(dev);
73212bd3c8bSSascha Wildner 	return (ENXIO);
73312bd3c8bSSascha Wildner }
73412bd3c8bSSascha Wildner 
73512bd3c8bSSascha Wildner 
73612bd3c8bSSascha Wildner static void
mos_attach_post(struct usb_ether * ue)73712bd3c8bSSascha Wildner mos_attach_post(struct usb_ether *ue)
73812bd3c8bSSascha Wildner {
73912bd3c8bSSascha Wildner 	struct mos_softc *sc = uether_getsc(ue);
74012bd3c8bSSascha Wildner 	int err;
741def76f9fSSascha Wildner #ifdef USB_DEBUG
7426a054f0bSSascha Wildner 	char ethstr[ETHER_ADDRSTRLEN + 1];
7436a054f0bSSascha Wildner #endif
74412bd3c8bSSascha Wildner 
74512bd3c8bSSascha Wildner 	/* Read MAC address, inform the world. */
74612bd3c8bSSascha Wildner 	err = mos_readmac(sc, ue->ue_eaddr);
74712bd3c8bSSascha Wildner 
74812bd3c8bSSascha Wildner 	if (err)
74912bd3c8bSSascha Wildner 	  MOS_DPRINTFN("couldn't get MAC address");
75012bd3c8bSSascha Wildner 
7516a054f0bSSascha Wildner 	MOS_DPRINTFN("address: %s", kether_ntoa(ue->ue_eaddr, ethstr));
75212bd3c8bSSascha Wildner 
75312bd3c8bSSascha Wildner 	mos_chip_init(sc);
75412bd3c8bSSascha Wildner }
75512bd3c8bSSascha Wildner 
75612bd3c8bSSascha Wildner static int
mos_detach(device_t dev)75712bd3c8bSSascha Wildner mos_detach(device_t dev)
75812bd3c8bSSascha Wildner {
75912bd3c8bSSascha Wildner 	struct mos_softc *sc = device_get_softc(dev);
76012bd3c8bSSascha Wildner 	struct usb_ether *ue = &sc->sc_ue;
76112bd3c8bSSascha Wildner 
76212bd3c8bSSascha Wildner 	usbd_transfer_unsetup(sc->sc_xfer, MOS_ENDPT_MAX);
76312bd3c8bSSascha Wildner 	uether_ifdetach(ue);
764559d4eaeSSascha Wildner 	lockuninit(&sc->sc_lock);
76512bd3c8bSSascha Wildner 
76612bd3c8bSSascha Wildner 	return (0);
76712bd3c8bSSascha Wildner }
76812bd3c8bSSascha Wildner 
76912bd3c8bSSascha Wildner 
77012bd3c8bSSascha Wildner 
77112bd3c8bSSascha Wildner 
77212bd3c8bSSascha Wildner /*
77312bd3c8bSSascha Wildner  * A frame has been uploaded: pass the resulting mbuf chain up to
77412bd3c8bSSascha Wildner  * the higher level protocols.
77512bd3c8bSSascha Wildner  */
77612bd3c8bSSascha Wildner static void
mos_bulk_read_callback(struct usb_xfer * xfer,usb_error_t error)77712bd3c8bSSascha Wildner mos_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
77812bd3c8bSSascha Wildner {
77912bd3c8bSSascha Wildner 	struct mos_softc *sc = usbd_xfer_softc(xfer);
78012bd3c8bSSascha Wildner 	struct usb_ether *ue = &sc->sc_ue;
78112bd3c8bSSascha Wildner 	struct ifnet *ifp = uether_getifp(ue);
78212bd3c8bSSascha Wildner 
78312bd3c8bSSascha Wildner 	uint8_t rxstat = 0;
78412bd3c8bSSascha Wildner 	uint32_t actlen;
78512bd3c8bSSascha Wildner 	uint16_t pktlen = 0;
78612bd3c8bSSascha Wildner 	struct usb_page_cache *pc;
78712bd3c8bSSascha Wildner 
78812bd3c8bSSascha Wildner 	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
78912bd3c8bSSascha Wildner 	pc = usbd_xfer_get_frame(xfer, 0);
79012bd3c8bSSascha Wildner 
79112bd3c8bSSascha Wildner 	switch (USB_GET_STATE(xfer)) {
79212bd3c8bSSascha Wildner 	case USB_ST_TRANSFERRED:
79312bd3c8bSSascha Wildner 		MOS_DPRINTFN("actlen : %d", actlen);
79412bd3c8bSSascha Wildner 		if (actlen <= 1) {
795f8577199SSascha Wildner 			IFNET_STAT_INC(ifp, ierrors, 1);
79612bd3c8bSSascha Wildner 			goto tr_setup;
79712bd3c8bSSascha Wildner 		}
79812bd3c8bSSascha Wildner 		/* evaluate status byte at the end */
79912bd3c8bSSascha Wildner 		usbd_copy_out(pc, actlen - sizeof(rxstat), &rxstat,
80012bd3c8bSSascha Wildner 		    sizeof(rxstat));
80112bd3c8bSSascha Wildner 
80212bd3c8bSSascha Wildner 		if (rxstat != MOS_RXSTS_VALID) {
80312bd3c8bSSascha Wildner 			MOS_DPRINTFN("erroneous frame received");
80412bd3c8bSSascha Wildner 			if (rxstat & MOS_RXSTS_SHORT_FRAME)
80512bd3c8bSSascha Wildner 				MOS_DPRINTFN("frame size less than 64 bytes");
80612bd3c8bSSascha Wildner 			if (rxstat & MOS_RXSTS_LARGE_FRAME) {
80712bd3c8bSSascha Wildner 				MOS_DPRINTFN("frame size larger than "
80812bd3c8bSSascha Wildner 				    "1532 bytes");
80912bd3c8bSSascha Wildner 			}
81012bd3c8bSSascha Wildner 			if (rxstat & MOS_RXSTS_CRC_ERROR)
81112bd3c8bSSascha Wildner 				MOS_DPRINTFN("CRC error");
81212bd3c8bSSascha Wildner 			if (rxstat & MOS_RXSTS_ALIGN_ERROR)
81312bd3c8bSSascha Wildner 				MOS_DPRINTFN("alignment error");
814f8577199SSascha Wildner 			IFNET_STAT_INC(ifp, ierrors, 1);
81512bd3c8bSSascha Wildner 			goto tr_setup;
81612bd3c8bSSascha Wildner 		}
81712bd3c8bSSascha Wildner 		/* Remember the last byte was used for the status fields */
81812bd3c8bSSascha Wildner 		pktlen = actlen - 1;
81912bd3c8bSSascha Wildner 		if (pktlen < sizeof(struct ether_header)) {
82012bd3c8bSSascha Wildner 			MOS_DPRINTFN("error: pktlen %d is smaller "
82112bd3c8bSSascha Wildner 			    "than ether_header %zd", pktlen,
82212bd3c8bSSascha Wildner 			    sizeof(struct ether_header));
823f8577199SSascha Wildner 			IFNET_STAT_INC(ifp, ierrors, 1);
82412bd3c8bSSascha Wildner 			goto tr_setup;
82512bd3c8bSSascha Wildner 		}
82612bd3c8bSSascha Wildner 		uether_rxbuf(ue, pc, 0, actlen);
82712bd3c8bSSascha Wildner 		/* FALLTHROUGH */
82812bd3c8bSSascha Wildner 	case USB_ST_SETUP:
82912bd3c8bSSascha Wildner tr_setup:
83012bd3c8bSSascha Wildner 		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
83112bd3c8bSSascha Wildner 		usbd_transfer_submit(xfer);
83212bd3c8bSSascha Wildner 		uether_rxflush(ue);
83312bd3c8bSSascha Wildner 		return;
83412bd3c8bSSascha Wildner 	default:
83512bd3c8bSSascha Wildner 		MOS_DPRINTFN("bulk read error, %s", usbd_errstr(error));
83612bd3c8bSSascha Wildner 		if (error != USB_ERR_CANCELLED) {
83712bd3c8bSSascha Wildner 			usbd_xfer_set_stall(xfer);
83812bd3c8bSSascha Wildner 			goto tr_setup;
83912bd3c8bSSascha Wildner 		}
84012bd3c8bSSascha Wildner 		MOS_DPRINTFN("start rx %i", usbd_xfer_max_len(xfer));
84112bd3c8bSSascha Wildner 		return;
84212bd3c8bSSascha Wildner 	}
84312bd3c8bSSascha Wildner }
84412bd3c8bSSascha Wildner 
84512bd3c8bSSascha Wildner /*
84612bd3c8bSSascha Wildner  * A frame was downloaded to the chip. It's safe for us to clean up
84712bd3c8bSSascha Wildner  * the list buffers.
84812bd3c8bSSascha Wildner  */
84912bd3c8bSSascha Wildner static void
mos_bulk_write_callback(struct usb_xfer * xfer,usb_error_t error)85012bd3c8bSSascha Wildner mos_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
85112bd3c8bSSascha Wildner {
85212bd3c8bSSascha Wildner 	struct mos_softc *sc = usbd_xfer_softc(xfer);
85312bd3c8bSSascha Wildner 	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
85412bd3c8bSSascha Wildner 	struct usb_page_cache *pc;
85512bd3c8bSSascha Wildner 	struct mbuf *m;
85612bd3c8bSSascha Wildner 
85712bd3c8bSSascha Wildner 
85812bd3c8bSSascha Wildner 
85912bd3c8bSSascha Wildner 	switch (USB_GET_STATE(xfer)) {
86012bd3c8bSSascha Wildner 	case USB_ST_TRANSFERRED:
86112bd3c8bSSascha Wildner 		MOS_DPRINTFN("transfer of complete");
862f8577199SSascha Wildner 		IFNET_STAT_INC(ifp, opackets, 1);
86312bd3c8bSSascha Wildner 		/* FALLTHROUGH */
86412bd3c8bSSascha Wildner 	case USB_ST_SETUP:
86512bd3c8bSSascha Wildner tr_setup:
86612bd3c8bSSascha Wildner 		/*
86712bd3c8bSSascha Wildner 		 * XXX: don't send anything if there is no link?
86812bd3c8bSSascha Wildner 		 */
869559d4eaeSSascha Wildner 		m = ifq_dequeue(&ifp->if_snd);
87012bd3c8bSSascha Wildner 		if (m == NULL)
87112bd3c8bSSascha Wildner 			return;
87212bd3c8bSSascha Wildner 
87312bd3c8bSSascha Wildner 		pc = usbd_xfer_get_frame(xfer, 0);
87412bd3c8bSSascha Wildner 		usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len);
87512bd3c8bSSascha Wildner 
87612bd3c8bSSascha Wildner 		usbd_xfer_set_frame_len(xfer, 0, m->m_pkthdr.len);
87712bd3c8bSSascha Wildner 
87812bd3c8bSSascha Wildner 
87912bd3c8bSSascha Wildner 		/*
88012bd3c8bSSascha Wildner 		 * if there's a BPF listener, bounce a copy
88112bd3c8bSSascha Wildner 		 * of this frame to him:
88212bd3c8bSSascha Wildner 		 */
88312bd3c8bSSascha Wildner 		BPF_MTAP(ifp, m);
88412bd3c8bSSascha Wildner 
88512bd3c8bSSascha Wildner 		m_freem(m);
88612bd3c8bSSascha Wildner 
88712bd3c8bSSascha Wildner 		usbd_transfer_submit(xfer);
88812bd3c8bSSascha Wildner 
889f8577199SSascha Wildner 		IFNET_STAT_INC(ifp, opackets, 1);
89012bd3c8bSSascha Wildner 		return;
89112bd3c8bSSascha Wildner 	default:
89212bd3c8bSSascha Wildner 		MOS_DPRINTFN("usb error on tx: %s\n", usbd_errstr(error));
893f8577199SSascha Wildner 		IFNET_STAT_INC(ifp, oerrors, 1);
89412bd3c8bSSascha Wildner 		if (error != USB_ERR_CANCELLED) {
89512bd3c8bSSascha Wildner 			usbd_xfer_set_stall(xfer);
89612bd3c8bSSascha Wildner 			goto tr_setup;
89712bd3c8bSSascha Wildner 		}
89812bd3c8bSSascha Wildner 		return;
89912bd3c8bSSascha Wildner 	}
90012bd3c8bSSascha Wildner }
90112bd3c8bSSascha Wildner 
90212bd3c8bSSascha Wildner static void
mos_tick(struct usb_ether * ue)90312bd3c8bSSascha Wildner mos_tick(struct usb_ether *ue)
90412bd3c8bSSascha Wildner {
90512bd3c8bSSascha Wildner 	struct mos_softc *sc = uether_getsc(ue);
90612bd3c8bSSascha Wildner 	struct mii_data *mii = GET_MII(sc);
90712bd3c8bSSascha Wildner 
908559d4eaeSSascha Wildner 	MOS_LOCK_ASSERT(sc);
90912bd3c8bSSascha Wildner 
91012bd3c8bSSascha Wildner 	mii_tick(mii);
91112bd3c8bSSascha Wildner 	if (!sc->mos_link && mii->mii_media_status & IFM_ACTIVE &&
91212bd3c8bSSascha Wildner 	    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
91312bd3c8bSSascha Wildner 		MOS_DPRINTFN("got link");
91412bd3c8bSSascha Wildner 		sc->mos_link++;
91512bd3c8bSSascha Wildner 		mos_start(ue);
91612bd3c8bSSascha Wildner 	}
91712bd3c8bSSascha Wildner }
91812bd3c8bSSascha Wildner 
91912bd3c8bSSascha Wildner 
92012bd3c8bSSascha Wildner static void
mos_start(struct usb_ether * ue)92112bd3c8bSSascha Wildner mos_start(struct usb_ether *ue)
92212bd3c8bSSascha Wildner {
92312bd3c8bSSascha Wildner 	struct mos_softc *sc = uether_getsc(ue);
92412bd3c8bSSascha Wildner 
92512bd3c8bSSascha Wildner 	/*
92612bd3c8bSSascha Wildner 	 * start the USB transfers, if not already started:
92712bd3c8bSSascha Wildner 	 */
92812bd3c8bSSascha Wildner 	usbd_transfer_start(sc->sc_xfer[MOS_ENDPT_TX]);
92912bd3c8bSSascha Wildner 	usbd_transfer_start(sc->sc_xfer[MOS_ENDPT_RX]);
93012bd3c8bSSascha Wildner 	usbd_transfer_start(sc->sc_xfer[MOS_ENDPT_INTR]);
93112bd3c8bSSascha Wildner }
93212bd3c8bSSascha Wildner 
93312bd3c8bSSascha Wildner static void
mos_init(struct usb_ether * ue)93412bd3c8bSSascha Wildner mos_init(struct usb_ether *ue)
93512bd3c8bSSascha Wildner {
93612bd3c8bSSascha Wildner 	struct mos_softc *sc = uether_getsc(ue);
93712bd3c8bSSascha Wildner 	struct ifnet *ifp = uether_getifp(ue);
93812bd3c8bSSascha Wildner 	uint8_t rxmode;
93912bd3c8bSSascha Wildner 
940559d4eaeSSascha Wildner 	MOS_LOCK_ASSERT(sc);
94112bd3c8bSSascha Wildner 
94212bd3c8bSSascha Wildner 	/* Cancel pending I/O and free all RX/TX buffers. */
94312bd3c8bSSascha Wildner 	mos_reset(sc);
94412bd3c8bSSascha Wildner 
94512bd3c8bSSascha Wildner 	/* Write MAC address */
94612bd3c8bSSascha Wildner 	mos_writemac(sc, IF_LLADDR(ifp));
94712bd3c8bSSascha Wildner 
94812bd3c8bSSascha Wildner 	/* Read and set transmitter IPG values */
94912bd3c8bSSascha Wildner 	sc->mos_ipgs[0] = mos_reg_read_1(sc, MOS_IPG0);
95012bd3c8bSSascha Wildner 	sc->mos_ipgs[1] = mos_reg_read_1(sc, MOS_IPG1);
95112bd3c8bSSascha Wildner 	mos_reg_write_1(sc, MOS_IPG0, sc->mos_ipgs[0]);
95212bd3c8bSSascha Wildner 	mos_reg_write_1(sc, MOS_IPG1, sc->mos_ipgs[1]);
95312bd3c8bSSascha Wildner 
95412bd3c8bSSascha Wildner 	/*
95512bd3c8bSSascha Wildner 	 * Enable receiver and transmitter, bridge controls speed/duplex
95612bd3c8bSSascha Wildner 	 * mode
95712bd3c8bSSascha Wildner 	 */
95812bd3c8bSSascha Wildner 	rxmode = mos_reg_read_1(sc, MOS_CTL);
95912bd3c8bSSascha Wildner 	rxmode |= MOS_CTL_RX_ENB | MOS_CTL_TX_ENB | MOS_CTL_BS_ENB;
96012bd3c8bSSascha Wildner 	rxmode &= ~(MOS_CTL_SLEEP);
96112bd3c8bSSascha Wildner 
96212bd3c8bSSascha Wildner 	mos_setpromisc(ue);
96312bd3c8bSSascha Wildner 
96412bd3c8bSSascha Wildner 	/* XXX: broadcast mode? */
96512bd3c8bSSascha Wildner 	mos_reg_write_1(sc, MOS_CTL, rxmode);
96612bd3c8bSSascha Wildner 
96712bd3c8bSSascha Wildner 	/* Load the multicast filter. */
96812bd3c8bSSascha Wildner 	mos_setmulti(ue);
96912bd3c8bSSascha Wildner 
970559d4eaeSSascha Wildner 	ifp->if_flags |= IFF_RUNNING;
97112bd3c8bSSascha Wildner 	mos_start(ue);
97212bd3c8bSSascha Wildner }
97312bd3c8bSSascha Wildner 
97412bd3c8bSSascha Wildner 
97512bd3c8bSSascha Wildner static void
mos_intr_callback(struct usb_xfer * xfer,usb_error_t error)97612bd3c8bSSascha Wildner mos_intr_callback(struct usb_xfer *xfer, usb_error_t error)
97712bd3c8bSSascha Wildner {
97812bd3c8bSSascha Wildner 	struct mos_softc *sc = usbd_xfer_softc(xfer);
97912bd3c8bSSascha Wildner 	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
98012bd3c8bSSascha Wildner 	struct usb_page_cache *pc;
98112bd3c8bSSascha Wildner 	uint32_t pkt;
98212bd3c8bSSascha Wildner 	int actlen;
98312bd3c8bSSascha Wildner 
984f8577199SSascha Wildner 	IFNET_STAT_INC(ifp, oerrors, 1);
98512bd3c8bSSascha Wildner 
98612bd3c8bSSascha Wildner 	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
98712bd3c8bSSascha Wildner 	MOS_DPRINTFN("actlen %i", actlen);
98812bd3c8bSSascha Wildner 
98912bd3c8bSSascha Wildner 	switch (USB_GET_STATE(xfer)) {
99012bd3c8bSSascha Wildner 	case USB_ST_TRANSFERRED:
99112bd3c8bSSascha Wildner 
99212bd3c8bSSascha Wildner 		pc = usbd_xfer_get_frame(xfer, 0);
99312bd3c8bSSascha Wildner 		usbd_copy_out(pc, 0, &pkt, sizeof(pkt));
99412bd3c8bSSascha Wildner 		/* FALLTHROUGH */
99512bd3c8bSSascha Wildner 	case USB_ST_SETUP:
99612bd3c8bSSascha Wildner tr_setup:
99712bd3c8bSSascha Wildner 		return;
99812bd3c8bSSascha Wildner 	default:
99912bd3c8bSSascha Wildner 		if (error != USB_ERR_CANCELLED) {
100012bd3c8bSSascha Wildner 			usbd_xfer_set_stall(xfer);
100112bd3c8bSSascha Wildner 			goto tr_setup;
100212bd3c8bSSascha Wildner 		}
100312bd3c8bSSascha Wildner 		return;
100412bd3c8bSSascha Wildner 	}
100512bd3c8bSSascha Wildner }
100612bd3c8bSSascha Wildner 
100712bd3c8bSSascha Wildner 
100812bd3c8bSSascha Wildner /*
100912bd3c8bSSascha Wildner  * Stop the adapter and free any mbufs allocated to the
101012bd3c8bSSascha Wildner  * RX and TX lists.
101112bd3c8bSSascha Wildner  */
101212bd3c8bSSascha Wildner static void
mos_stop(struct usb_ether * ue)101312bd3c8bSSascha Wildner mos_stop(struct usb_ether *ue)
101412bd3c8bSSascha Wildner {
101512bd3c8bSSascha Wildner 	struct mos_softc *sc = uether_getsc(ue);
101612bd3c8bSSascha Wildner 	struct ifnet *ifp = uether_getifp(ue);
101712bd3c8bSSascha Wildner 
101812bd3c8bSSascha Wildner 	mos_reset(sc);
101912bd3c8bSSascha Wildner 
1020559d4eaeSSascha Wildner 	MOS_LOCK_ASSERT(sc);
1021559d4eaeSSascha Wildner 	ifp->if_flags &= ~IFF_RUNNING;
102212bd3c8bSSascha Wildner 
102312bd3c8bSSascha Wildner 	/* stop all the transfers, if not already stopped */
102412bd3c8bSSascha Wildner 	usbd_transfer_stop(sc->sc_xfer[MOS_ENDPT_TX]);
102512bd3c8bSSascha Wildner 	usbd_transfer_stop(sc->sc_xfer[MOS_ENDPT_RX]);
102612bd3c8bSSascha Wildner 	usbd_transfer_stop(sc->sc_xfer[MOS_ENDPT_INTR]);
102712bd3c8bSSascha Wildner 
102812bd3c8bSSascha Wildner 	sc->mos_link = 0;
102912bd3c8bSSascha Wildner }
1030