/*-
 * Copyright (c) 1997, 1998, 1999, 2000-2003
 *	Bill Paul <wpaul@windriver.com>.  All rights reserved.
 * Copyright (c) 2007 Ravikanth Gadeela(ravikanthdrdl@yahoo.com)
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by Ravi Kanth.
 * 4. Neither the name of the author nor the names of any co-contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
	
 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul, THE VOICES IN HIS HEAD OR
 * THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/sys/dev/usb/if_mos.c,v 1.30.2.4 2006/03/17 21:30:56 glebius Exp $");

/*
 * MOSCHIP Technologies Ltd MOS7830 USB 2.0 ethernet driver.  
 *
 * Manuals available from:
 * http://www.moschip.com/data/products/MCS7830/Data%20Sheet_7830DA.pdf
 *
 * Written by Ravikanth Gadeela <ravikanthg@moschip.com>
 * Senior Engineer
 * Moschip Semiconductor Technologies Ltd
 */

/*
 * The Mos7830 provides USB ethernet supports at 10 and 100Mbps.
 *
 *
 * Note that this device appears to only support loading the station
 * address via autload from the EEPROM (i.e. there's no way to manaully
 * set it).
 *
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/sockio.h>
#include <sys/mbuf.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/socket.h>


#include <net/if.h>
#include <net/if_arp.h>
#include <net/ethernet.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/if_types.h>

#include <net/bpf.h>

#include <sys/bus.h>
#include <machine/bus.h>
#if __FreeBSD_version < 500000
#include <machine/clock.h>
#endif

#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdi_util.h>
#include <dev/usb/usbdivar.h>
#include "usbdevs.h"
#include <dev/usb/usb_ethersubr.h>

#include <dev/mii/mii.h>
#include <dev/mii/miivar.h>

/* "controller miibus0" required.  See GENERIC if you get errors here. */
#include "/usr/src/sys/dev/tdfx/tdfx_io.h"
#include "miibus_if.h"

#include "if_mosreg.h"

#ifndef USB_VENDOR_MOSCHIP
#define USB_VENDOR_MOSCHIP 0x9710
#endif
#ifndef USB_PRODUCT_MOSCHIP_MOS7830
#define USB_PRODUCT_MOSCHIP_MOS7830 0x7830
#endif

//#define abcd	0
//#define MOS_DEBUG       0
//#define MOS_TXDEBUG       0
//#define MOS_RXDEBUG       0

#ifdef MOS_DEBUG
#define dprintf(fmt,args...)    printf("%s:"fmt,__FUNCTION__,##args)
#else
#define dprintf(fmt,args...)
#endif

#ifdef MOS_TXDEBUG
#define txprintf(fmt,args...)    printf("%s:"fmt,__FUNCTION__,##args)
#else
#define txprintf(fmt,args...)
#endif

#ifdef MOS_RXDEBUG
#define rxprintf(fmt,args...)    printf("%s:"fmt,__FUNCTION__,##args)
#else
#define rxprintf(fmt,args...)
#endif

 /* Various supported device vendors/products.
 */
Static struct mos_type mos_devs[] = {
	{ USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MOS7830 },
	{ 0, 0 }
};

Static int mos_match(device_ptr_t);
Static int mos_attach(device_ptr_t);
Static int mos_detach(device_ptr_t);
Static void mos_shutdown(device_ptr_t);
Static void mos_stop(struct mos_softc *);
Static void mos_reset(struct mos_softc *);
Static int mos_initialize_device(struct mos_softc *);
Static int mos_cmd(struct mos_softc *,u_int8_t,u_int8_t,int,u_int8_t *,int);


Static int autoNegChangeMode(struct mos_softc *,int);
Static int getVendorCommand(struct mos_softc *,u_int16_t,u_int16_t,u_int8_t * );
Static int setVendorCommand(struct mos_softc *,u_int16_t,u_int16_t,u_int8_t *);
Static int mos_rwPHYRegPassive(struct mos_softc *,u_int8_t,u_int16_t *,u_int8_t);


Static int mos_ioctl(struct ifnet *, u_long, caddr_t);
Static void mos_start(struct ifnet *);
Static void mos_watchdog(struct ifnet *);
Static void mos_init(void *);
Static void mos_rxstart(struct ifnet *);
Static int mos_encap(struct mos_softc *, struct mbuf *, int);
Static void mos_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
Static void mos_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
#ifdef abcd
Static void mos_tick(void *);
#endif
Static void mos_setmulti(struct mos_softc *);
Static int mos_miibus_readreg(device_ptr_t, int, int);
Static int mos_miibus_writereg(device_ptr_t, int, int, int);
//Static void mos_miibus_statchg(device_ptr_t);
//Static void mos_mediainit(device_ptr_t);

Static int mos_ifmedia_upd(struct ifnet *);
Static void mos_ifmedia_sts(struct ifnet *, struct ifmediareq *);
Static device_method_t mos_methods[] = {
	/* Device interface */
	DEVMETHOD(device_probe,		mos_match),
	DEVMETHOD(device_attach,	mos_attach),
	DEVMETHOD(device_detach,	mos_detach),
	DEVMETHOD(device_shutdown,	mos_shutdown),
	/* bus interface */
        DEVMETHOD(bus_print_child,      bus_generic_print_child),
        DEVMETHOD(bus_driver_added,     bus_generic_driver_added),
	/* MII interface */
	//DEVMETHOD(miibus_mediainit,	mos_mediainit),
        DEVMETHOD(miibus_readreg,       mos_miibus_readreg),
        DEVMETHOD(miibus_writereg,      mos_miibus_writereg),
       // DEVMETHOD(miibus_statchg,       mos_miibus_statchg),
	{ 0, 0 }
};

Static driver_t mos_driver = {
	"mos",
	mos_methods,
	sizeof(struct mos_softc)
};

Static devclass_t mos_devclass;

DRIVER_MODULE(mos, uhub, mos_driver, mos_devclass, usbd_driver_load, 0);
DRIVER_MODULE(miibus, mos, miibus_driver, miibus_devclass, 0, 0);
MODULE_DEPEND(mos, usb, 1, 1, 1);
MODULE_DEPEND(mos, miibus, 1, 1, 1);
Static int
mos_cmd(struct mos_softc *sc,u_int8_t request,u_int8_t rtype,int index,u_int8_t *buf,int len)
{
	usb_device_request_t	req;
	usbd_status		err;

	if (sc->mos_dying)
		return(0);
	req.bRequest = request;
	req.bmRequestType = rtype;
	USETW(req.wValue, 0);
	USETW(req.wIndex, index);
	USETW(req.wLength, len);

	err = usbd_do_request(sc->mos_udev, &req, buf);

	if (err)
		return(-1);

	return(0);
}

Static void
mos_reset(struct mos_softc *sc)
{
	if (sc->mos_dying)
		return;

	if (usbd_set_config_no(sc->mos_udev, MOS_CONFIG_NO, 1) ||
	    usbd_device2interface_handle(sc->mos_udev, MOS_IFACE_IDX,
	    &sc->mos_iface)) {
		printf("mos%d: getting interface handle failed\n",
		    sc->mos_unit);
	}

	/* Wait a little while for the chip to get its brains in order. */
	DELAY(1000);
	return;
}

/*
 * Probe for a AX88172 chip.
 */
USB_MATCH(mos)
{
	USB_MATCH_START(mos, uaa);
	struct mos_type			*t;

	if (!uaa->iface)
		return(UMATCH_NONE);

	t = mos_devs;
	while(t->mos_vid) {
		if (uaa->vendor == t->mos_vid &&
		    uaa->product == t->mos_did) {
			return(UMATCH_VENDOR_PRODUCT);
		}
		t++;
	}

	return(UMATCH_NONE);
}

/*
 * Attach the interface. Allocate softc structures, do ifmedia
 * setup and ethernet/BPF attach.
 */
USB_ATTACH(mos)
{
	USB_ATTACH_START(mos, sc, uaa);
	char			devinfo[1024];
	struct ifnet		*ifp;
	usb_interface_descriptor_t	*id;
	usb_endpoint_descriptor_t	*ed;
	u_int16_t	retval=0;
	int			i;

	bzero(sc, sizeof(struct mos_softc));
	sc->mos_udev = uaa->device;
	sc->mos_dev = self;
	sc->mos_unit = device_get_unit(self);

	if (usbd_set_config_no(sc->mos_udev, MOS_CONFIG_NO, 1)) {
		printf("mos%d: getting interface handle failed\n",
		    sc->mos_unit);
		USB_ATTACH_ERROR_RETURN;
	}

	if (usbd_device2interface_handle(uaa->device,
	    MOS_IFACE_IDX, &sc->mos_iface)) {
		printf("mos%d: getting interface handle failed\n",
		    sc->mos_unit);
		USB_ATTACH_ERROR_RETURN;
	}

	id = usbd_get_interface_descriptor(sc->mos_iface);

	usbd_devinfo(uaa->device, 0, devinfo);
	device_set_desc_copy(self, devinfo);
	printf("%s: %s\n", USBDEVNAME(self), devinfo);

	/* Find endpoints. */
	for (i = 0; i < id->bNumEndpoints; i++) {
		ed = usbd_interface2endpoint_descriptor(sc->mos_iface, i);
		if (!ed) {
			printf("mos%d: couldn't get ep %d\n",
			    sc->mos_unit, i);
			USB_ATTACH_ERROR_RETURN;
		}
		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
			sc->mos_ed[MOS_ENDPT_RX] = ed->bEndpointAddress;
		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
			sc->mos_ed[MOS_ENDPT_TX] = ed->bEndpointAddress;
			memcpy(&sc->mos_maxpacket,ed->wMaxPacketSize,sizeof(uWord));	
			//sc->mos_maxpacket =(u_int16_t) ed->wMaxPacketSize;
			printf(" mos_maxpacket:%d\n",sc->mos_maxpacket);
		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
			sc->mos_ed[MOS_ENDPT_INTR] = ed->bEndpointAddress;
		}
	}
	//printf("rendpoint:%x wendpoint:%x xendpoint:%x\n",sc->mos_ed[MOS_ENDPT_RX],sc->mos_ed[MOS_ENDPT_TX],sc->mos_ed[MOS_ENDPT_INTR]);

	mos_initialize_device(sc);// initialize device,get mac id and set speed
       	// Initialize the mutex locks 
	mtx_init(&sc->mos_mtx, device_get_nameunit(self), MTX_NETWORK_LOCK,
            MTX_DEF | MTX_RECURSE);
	MOS_LOCK(sc);
	sc->mos_phyaddrs[0] = sc->mos_phyaddrs[1] = 0xFF;

        ifp = sc->mos_ifp = if_alloc(IFT_ETHER);
        if (ifp == NULL) {
                printf("mos%d: can not if_alloc()\n", sc->mos_unit);
                MOS_UNLOCK(sc);
                mtx_destroy(&sc->mos_mtx);
                USB_ATTACH_ERROR_RETURN;
        }
        ifp->if_softc = sc;
        if_initname(ifp, "mos", sc->mos_unit);
        ifp->if_mtu = ETHERMTU;
        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST |
            IFF_NEEDSGIANT;
	ifp->if_ioctl = mos_ioctl;
        ifp->if_start = mos_start;
        ifp->if_watchdog = mos_watchdog;
        ifp->if_init = mos_init;
	//ifp->if_baudrate = 11000000;
        ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;

        sc->mos_qdat.ifp = ifp;
        sc->mos_qdat.if_rxstart = mos_rxstart;
	retval = mii_phy_probe(self, &sc->mos_miibus,mos_ifmedia_upd, mos_ifmedia_sts);
	dprintf("return value of mii_phy_probe:%d\n",retval);
	if(retval)
	{
		 printf("mos%d: MII without any PHY!\n", sc->mos_unit);
                if_free(ifp);
                MOS_UNLOCK(sc);
                mtx_destroy(&sc->mos_mtx);
                USB_ATTACH_ERROR_RETURN;
	}
	 /*
         * Call MI attach routine.
         */
        ether_ifattach(ifp, sc->eaddr);
        callout_handle_init(&sc->mos_stat_ch);
        usb_register_netisr();

        sc->mos_dying = 0;

        MOS_UNLOCK(sc);
	USB_ATTACH_SUCCESS_RETURN;
}

Static int mos_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
{
	//dprintf("\n");
	 struct mos_softc        *sc = ifp->if_softc;
        struct ifreq            *ifr = (struct ifreq *)data;
        struct mii_data         *mii;
        //u_int16_t               rxmode;
        int                     error = 0;

	dprintf("command:%08x size:%d\n",(int)_IOC_NR(command),(int)_IOC_SIZE(command));
	switch(command) {
		case SIOCGIFMEDIA:
        case SIOCSIFMEDIA:
                mii = GET_MII(sc);
                error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
                break;
	case SIOCADDMULTI:
        case SIOCDELMULTI:
                mos_setmulti(sc);
         	error = 0;
              	break;
	case SIOCSIFFLAGS:
                if (ifp->if_flags & IFF_UP) {
                        if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
                                mos_init(sc);
                } else {
                        if (ifp->if_drv_flags & IFF_DRV_RUNNING)
                                mos_stop(sc);
                }
                error = 0;
                break;
        default:
                error = ether_ioctl(ifp, command, data);
                break;
        }

        MOS_UNLOCK(sc);

        return(error);
}
Static void mos_start(struct ifnet *ifp)
{
	 struct mos_softc        *sc;
        struct mbuf             *m_head = NULL;

	txprintf("\n");
        sc = ifp->if_softc;
        MOS_LOCK(sc);
/*
        if (!sc->mos_link) {
                MOS_UNLOCK(sc);
                return;
        }
*/
        if (ifp->if_drv_flags & IFF_DRV_OACTIVE) {
                MOS_UNLOCK(sc);
                return;
        }

        IF_DEQUEUE(&ifp->if_snd, m_head);
        if (m_head == NULL) {
                MOS_UNLOCK(sc);
                return;
        }

	 if (mos_encap(sc, m_head, 0)) {
                IF_PREPEND(&ifp->if_snd, m_head);
                ifp->if_drv_flags |= IFF_DRV_OACTIVE;
                MOS_UNLOCK(sc);
                return;
        }

        /*
         * If there's a BPF listener, bounce a copy of this frame
         * to him.
         */
        BPF_MTAP(ifp, m_head);

        ifp->if_drv_flags |= IFF_DRV_OACTIVE;

        /*
         * Set a timeout in case the chip goes out to lunch.
         */
        ifp->if_timer = 5;
        MOS_UNLOCK(sc);


	return;
}
Static void mos_watchdog(struct ifnet *ifp)
{
 struct mos_softc        *sc;
        struct ue_chain *c;
        usbd_status             stat;

	dprintf("\n");
        sc = ifp->if_softc;
        MOS_LOCK(sc);

        ifp->if_oerrors++;
        printf("mos%d: watchdog timeout\n", sc->mos_unit);

        c = &sc->mos_cdata.ue_tx_chain[0];
        usbd_get_xfer_status(c->ue_xfer, NULL, NULL, NULL, &stat);
        mos_txeof(c->ue_xfer, c, stat);

        MOS_UNLOCK(sc);

        if (ifp->if_snd.ifq_head != NULL)
                mos_start(ifp);

        return;

}
Static void mos_init(void *xsc)
{
	struct mos_softc        *sc = xsc;
        struct ifnet            *ifp = sc->mos_ifp;
        struct ue_chain *c;
        usbd_status             err;
        int                     i;
//        int                     rxmode;

	dprintf("\n");
        if (ifp->if_drv_flags & IFF_DRV_RUNNING)
                return;

        MOS_LOCK(sc);

        /*
         * Cancel pending I/O and free all RX/TX buffers.
         */

        mos_reset(sc);

        /* Init Zero TX ring. */
        if (usb_ether_tx_list_init(sc, &sc->mos_zcdata,
            sc->mos_udev) == ENOBUFS) {
                printf("mos%d: zero tx list init failed\n", sc->mos_unit);
                MOS_UNLOCK(sc);
                return;
        }
	
	 /* Enable RX logic. */

        /* Init TX ring. */
        if (usb_ether_tx_list_init(sc, &sc->mos_cdata,
            sc->mos_udev) == ENOBUFS) {
                printf("mos%d: tx list init failed\n", sc->mos_unit);
                MOS_UNLOCK(sc);
                return;
        }

        /* Init RX ring. */
        if (usb_ether_rx_list_init(sc, &sc->mos_cdata,
            sc->mos_udev) == ENOBUFS) {
                printf("mos%d: rx list init failed\n", sc->mos_unit);
                MOS_UNLOCK(sc);
                return;
        }
	mos_setmulti(sc);
	
	 /* Open RX and TX pipes. */
        err = usbd_open_pipe(sc->mos_iface, sc->mos_ed[MOS_ENDPT_RX],
            USBD_EXCLUSIVE_USE, &sc->mos_ep[MOS_ENDPT_RX]);
        if (err) {
                printf("mos%d: open rx pipe failed: %s\n",
                    sc->mos_unit, usbd_errstr(err));
                MOS_UNLOCK(sc);
                return;
        }

        err = usbd_open_pipe(sc->mos_iface, sc->mos_ed[MOS_ENDPT_TX],
            USBD_EXCLUSIVE_USE, &sc->mos_ep[MOS_ENDPT_TX]);
        if (err) {
                printf("mos%d: open tx pipe failed: %s\n",
                    sc->mos_unit, usbd_errstr(err));
                MOS_UNLOCK(sc);
                return;
        }

	
        /* Start up the receive pipe. */
        for (i = 0; i < UE_RX_LIST_CNT; i++) {
                c = &sc->mos_cdata.ue_rx_chain[i];
                usbd_setup_xfer(c->ue_xfer, sc->mos_ep[MOS_ENDPT_RX],
                    c, mtod(c->ue_mbuf, char *),UE_BUFSZ,
                    USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, mos_rxeof);
                usbd_transfer(c->ue_xfer);
        }

        ifp->if_drv_flags |= IFF_DRV_RUNNING;
        ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;

        MOS_UNLOCK(sc);
#ifdef abcd
        sc->mos_stat_ch = timeout(mos_tick, sc, hz*2);
#endif

	return;
}
Static int
mos_encap(struct mos_softc *sc, struct mbuf *m, int idx)
{
        struct ue_chain *c;
        struct ue_chain *zc;
        usbd_status             err;

	txprintf("\n");
        c = &sc->mos_cdata.ue_tx_chain[idx];
	zc = &sc->mos_zcdata.ue_tx_chain[idx];
	txprintf(" packet length:%d\n",m->m_pkthdr.len);
        /*
         * Copy the mbuf data into a contiguous buffer, leaving two
         * bytes at the beginning to hold the frame length.
         */
        m_copydata(m, 0, m->m_pkthdr.len, c->ue_buf);
        c->ue_mbuf = m;

        usbd_setup_xfer(c->ue_xfer, sc->mos_ep[MOS_ENDPT_TX],
            c, c->ue_buf, m->m_pkthdr.len, USBD_FORCE_SHORT_XFER,
            10000, mos_txeof);

        /* Transmit */
        err = usbd_transfer(c->ue_xfer);
        if (err != USBD_IN_PROGRESS) {
                mos_stop(sc);
                return(EIO);
	 }
	if((m->m_pkthdr.len % sc->mos_maxpacket)==0)
	{
	txprintf(" zero length packet added to the current packet\n");
       	usbd_setup_xfer(zc->ue_xfer, sc->mos_ep[MOS_ENDPT_TX],
            zc, zc->ue_buf,1, USBD_FORCE_SHORT_XFER,
            10000, NULL);
        /* Zero length packet Transmit */
        err = usbd_transfer(zc->ue_xfer);
        if (err != USBD_IN_PROGRESS) {
                mos_stop(sc);
                return(EIO);
	 }
		
	}

        sc->mos_cdata.ue_tx_cnt++;

        return(0);
}

/*
 * A frame was downloaded to the chip. It's safe for us to clean up
 * the list buffers.
 */

Static void
mos_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
{
        struct mos_softc        *sc;
        struct ue_chain *c;
        struct ifnet            *ifp;
        usbd_status             err;
	txprintf("\n");
        c = priv;
        sc = c->ue_sc;
        MOS_LOCK(sc);
        ifp = sc->mos_ifp;

        if (status != USBD_NORMAL_COMPLETION) {
                if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
                        MOS_UNLOCK(sc);
                        return;
                }
 		printf("mos%d: usb error on tx: %s\n", sc->mos_unit,
                    usbd_errstr(status));
                if (status == USBD_STALLED)
                        usbd_clear_endpoint_stall(sc->mos_ep[MOS_ENDPT_TX]);
                MOS_UNLOCK(sc);
                return;
        }

        ifp->if_timer = 0;
        ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
        usbd_get_xfer_status(c->ue_xfer, NULL, NULL, NULL, &err);

        if (c->ue_mbuf != NULL) {
                c->ue_mbuf->m_pkthdr.rcvif = ifp;
                usb_tx_done(c->ue_mbuf);
                c->ue_mbuf = NULL;
        }

        if (err)
                ifp->if_oerrors++;
        else
                ifp->if_opackets++;

        MOS_UNLOCK(sc);

        return;
}
/*
 * A frame has been uploaded: pass the resulting mbuf chain up to
 * the higher level protocols.
 */
Static void
mos_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
{
        struct mos_softc        *sc;
        struct ue_chain *c;
        struct mbuf             *m;
        struct ifnet            *ifp;
        int                     total_len = 0;
	rxprintf("\n");
        c = priv;
        sc = c->ue_sc;
        MOS_LOCK(sc);
        ifp = sc->mos_ifp;

        if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
                MOS_UNLOCK(sc);
                return;
        }
 if (status != USBD_NORMAL_COMPLETION) {
                if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
                        MOS_UNLOCK(sc);
                        return;
                }
                if (usbd_ratecheck(&sc->mos_rx_notice))
                        printf("mos%d: usb error on rx: %s\n", sc->mos_unit,
                            usbd_errstr(status));
                if (status == USBD_STALLED)
                        usbd_clear_endpoint_stall(sc->mos_ep[MOS_ENDPT_RX]);
                goto done;
        }

        usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);

        m = c->ue_mbuf;

        if (total_len < sizeof(struct ether_header)) {
                ifp->if_ierrors++;
                goto done;
        }

        ifp->if_ipackets++;
        m->m_pkthdr.rcvif = (void *)&sc->mos_qdat;
 	m->m_pkthdr.len = m->m_len = total_len-1;
//	dprintf(" m_pkthdr.len:%d\n",m->m_pkthdr.len);

        /* Put the packet on the special USB input queue. */
        usb_ether_input(m);
        MOS_UNLOCK(sc);

        return;
done:
        /* Setup new transfer. */
        usbd_setup_xfer(c->ue_xfer, sc->mos_ep[MOS_ENDPT_RX],
            c, mtod(c->ue_mbuf, char *),UE_BUFSZ, USBD_SHORT_XFER_OK,
            USBD_NO_TIMEOUT, mos_rxeof);
        usbd_transfer(c->ue_xfer);
        MOS_UNLOCK(sc);

        return;
}
#ifdef abcd
Static void
mos_tick(void *xsc)
{
        struct mos_softc        *sc;
        struct ifnet            *ifp;
        struct mii_data         *mii;

        sc = xsc;

        if (sc == NULL)
                return;
	dprintf("\n");
        MOS_LOCK(sc);

        ifp = sc->mos_ifp;
        mii = GET_MII(sc);
        if (mii == NULL) {
                MOS_UNLOCK(sc);
                return;
        }
	 mii_tick(mii);
        if (!sc->mos_link && mii->mii_media_status & IFM_ACTIVE &&
            IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
                sc->mos_link++;
                if (ifp->if_snd.ifq_head != NULL)
                        mos_start(ifp);
        }

        sc->mos_stat_ch = timeout(mos_tick, sc, hz*2);

        MOS_UNLOCK(sc);

        return;
}
#endif

Static void mos_setmulti(struct mos_softc *sc)
{
	struct ifnet            *ifp;
        //struct ifmultiaddr      *ifma;
        //u_int32_t               h = 0;
        u_int16_t               status;
//        u_int8_t                hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
	u_int8_t		readHIFVal;

        ifp = sc->mos_ifp;

        MOS_LOCK(sc);
	
	if (ifp->if_flags & IFF_ALLMULTI)
	{
		sc->HIF_REG_15_val |= HIF_REG_15_ALLMULTICAST;
		dprintf(" All multi cast mode enabled\n");
	}
	else
	{
		sc->HIF_REG_15_val &= ~HIF_REG_15_ALLMULTICAST;
		dprintf(" All multi cast mode disabled\n");
	}
	if (ifp->if_flags & IFF_PROMISC)
	{
		sc->HIF_REG_15_val |= HIF_REG_15_PROMISCIOUS;
		dprintf(" Promiscious mode enabled\n");
	}
	else
	{
		sc->HIF_REG_15_val &= ~HIF_REG_15_PROMISCIOUS;
		dprintf(" Promiscious mode disabled\n");
	}
	status = setVendorCommand(sc,HIF_REG_15,1,&sc->HIF_REG_15_val);
	if(status)
		dprintf("HIF_REG_15 failed\n");
	status = 0;
	status = getVendorCommand(sc,HIF_REG_15,1,&readHIFVal);
	//dprintf(" read value of HIF_REG_15:%d\n",readHIFVal);
	if(status)
		dprintf("HIF_REG_15 failed\n");

        MOS_UNLOCK(sc);
	return;
}

Static int mos_miibus_readreg(device_ptr_t dev, int phy, int reg)
{
	struct mos_softc        *sc = USBGETSOFTC(dev);
 //     usbd_status             err;
	int		status=0;
        u_int16_t               val=0;
	u_int16_t		retvalue=0;
	u_int16_t		phyControlReg=0;

        if (sc->mos_dying)
                return(0);
	//dprintf("phy :%08x reg:%08x\n",phy,reg);

	if (sc->mos_phyaddrs[0] != 0xFF && sc->mos_phyaddrs[0] != phy)
                return (0);
	DELAY(50000);	
	MOS_LOCK(sc);

	if(reg==0)
	{
	status=mos_rwPHYRegPassive(sc,PHY_CONTROL_REG_INDEX,&phyControlReg,READ_OPCODE);
		if(phyControlReg & PHY_CONTROL_SPEED100)
		{
			if(phyControlReg & PHY_CONTROL_FULLDUPLEX)
			{
				//dprintf(" 100 Full Duplex\n");
				sc->HIF_REG_15_val |= HIF_REG_15_FULLDUPLEX_ENABLE;
				sc->HIF_REG_15_val |= HIF_REG_15_SPEED_100;
				setVendorCommand(sc,HIF_REG_15,1,&sc->HIF_REG_15_val);
				//retvalue=BMSR_100TXFDX;
			}
			else
			{
				//dprintf(" 100 Half Duplex\n");
				sc->HIF_REG_15_val &= ~HIF_REG_15_FULLDUPLEX_ENABLE;
				sc->HIF_REG_15_val |= HIF_REG_15_SPEED_100;
				setVendorCommand(sc,HIF_REG_15,1,&sc->HIF_REG_15_val);
				//retvalue=BMSR_100TXHDX;
				//retvalue=(BMCR_S100|ANAR_TX|ANAR_CSMA);
			}
		}
		else
		{
			if(phyControlReg & PHY_CONTROL_FULLDUPLEX)
			{
				//dprintf(" 10 Full Duplex\n");
				sc->HIF_REG_15_val |= HIF_REG_15_FULLDUPLEX_ENABLE;
				sc->HIF_REG_15_val &= ~HIF_REG_15_SPEED_100;
				setVendorCommand(sc,HIF_REG_15,1,&sc->HIF_REG_15_val);
				//retvalue=BMSR_10TFDX;
				//retvalue=(BMCR_S100|ANAR_10_FD|ANAR_CSMA);
			}
			else
			{
				//dprintf(" 10 Half Duplex\n");
				sc->HIF_REG_15_val &= ~HIF_REG_15_FULLDUPLEX_ENABLE;
				sc->HIF_REG_15_val &= ~HIF_REG_15_SPEED_100;
				setVendorCommand(sc,HIF_REG_15,1,&sc->HIF_REG_15_val);
				//retvalue=BMSR_10THDX;
				//retvalue=(ANAR_10|ANAR_CSMA);
			}
		}
		//sc->mos_tspeed = retvalue;
		//return(phyControlReg);
		retvalue = phyControlReg;
	}
	if(reg==1)
	{
		status=0;
		status=mos_rwPHYRegPassive(sc,PHY_STATUS_REG_INDEX,&val,READ_OPCODE);
		if(val & PHY_STATUS_REG_LINK_STATUS)
		{
		//	dprintf(" Link is OK!!\n");
			//retvalue=sc->mos_tspeed | LINK_OK;
			//retvalue= LINK_OK;
		}
		else
		{
		//	dprintf(" NO Link!!\n");
			//retvalue|=LINK_NOT_OK;
			//retvalue=LINK_NOT_OK;
		}
		
	//	return (val);
		retvalue= val;
	}
	MOS_UNLOCK(sc);
	if (val)
                sc->mos_phyaddrs[0] = phy;
//	dprintf(" return value:%08x\n",retvalue);
	return (retvalue);
}
Static int mos_miibus_writereg(device_ptr_t dev, int phy, int reg, int val)
{
 	struct mos_softc        *sc = USBGETSOFTC(dev);
        //usbd_status             err;
	int		status=0;
	
        if (sc->mos_dying)
                return(0);
//	dprintf("phy :%08x reg:%08x val:%08x\n",phy,reg,val);
	MOS_LOCK(sc);
	if(reg==0)
	{
		if(val & MOS_RESET)
		{
			status=mos_rwPHYRegPassive(sc,PHY_CONTROL_REG_INDEX,(u_int16_t *)&val,WRITE_OPCODE);
			//dprintf(" reset val:%08x status:%x\n",val,status);
		}
		else
		{
			if(val & MOS_100_10_SPEED)
			{
				if(val & MOS_FD_SPEED)
				{
					dprintf("Setting 100 Full Enabled\n");
					autoNegChangeMode(sc,4);
				}
				else
				{
					dprintf("Setting 100 Half Enabled\n");
					autoNegChangeMode(sc,3);
				}
			}
			else
			{
				if(val & MOS_FD_SPEED)
				{
					dprintf("Setting 10 Full Enabled\n");
					autoNegChangeMode(sc,2);
				}
				else
				{
					dprintf("Setting 10 Half Enabled\n");
					autoNegChangeMode(sc,1);
				}

			}
		}
	}
	
	MOS_UNLOCK(sc);
	return 0;	
}
/*
Static void mos_miibus_statchg(device_ptr_t dev)
{
dprintf("\n");
return;
}
*/
/*
Static void mos_mediainit(device_ptr_t dev)
{
	dprintf("\n");
	struct mos_softc *sc=device_get_softc(dev);
        struct mii_data *mii = GET_MII(sc);
        struct ifmedia *ifm;
        int media;

        //sc = device_get_softc(dev);
	//mii = GET_MII(sc);
        ifm = &mii->mii_media;
	media = IFM_ETHER | IFM_10_T;
        ifmedia_add(ifm, media, 0, 0);
	media = IFM_ETHER | IFM_100_TX;
        ifmedia_add(ifm, media, 0, 0);
	return;
}
*/
Static void mos_rxstart(struct ifnet *ifp)
{
	 struct mos_softc        *sc;
        struct ue_chain *c;

	rxprintf("\n");
        sc = ifp->if_softc;
        MOS_LOCK(sc);
/*	if (sc->mos_dying || !(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
                MOS_UNLOCK(sc);
                return;
        }*/

        c = &sc->mos_cdata.ue_rx_chain[sc->mos_cdata.ue_rx_prod];

        c->ue_mbuf = usb_ether_newbuf();
        if (c->ue_mbuf == NULL) {
                printf("%s: no memory for rx list "
                    "-- packet dropped!\n", USBDEVNAME(sc->mos_dev));
                ifp->if_ierrors++;
                MOS_UNLOCK(sc);
                return;
        }

        /* Setup new transfer. */
        usbd_setup_xfer(c->ue_xfer, sc->mos_ep[MOS_ENDPT_RX],
            c, mtod(c->ue_mbuf, char *),UE_BUFSZ, USBD_SHORT_XFER_OK,
            USBD_NO_TIMEOUT, mos_rxeof);
        usbd_transfer(c->ue_xfer);
        MOS_UNLOCK(sc);

	return;
}
Static int mos_ifmedia_upd(struct ifnet *ifp)
{
	struct mos_softc        *sc = ifp->if_softc;
        struct mii_data         *mii = GET_MII(sc);
	dprintf("\n");
        sc->mos_link = 0;
        if (mii->mii_instance) {
                struct mii_softc        *miisc;
                LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
                         mii_phy_reset(miisc);
        }
        mii_mediachg(mii);
        return (0);
}
Static void mos_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
{
	  struct mos_softc        *sc = ifp->if_softc;
        struct mii_data         *mii = GET_MII(sc);

	dprintf("\n");
        mii_pollstat(mii);
        ifmr->ifm_active = mii->mii_media_active;
        ifmr->ifm_status = mii->mii_media_status;
        return;
}
//#endif
// Get vendor specific command
Static int getVendorCommand(struct mos_softc *sc,u_int16_t reg_index,u_int16_t length,u_int8_t * data)
{
int status=0;
status=mos_cmd(sc,MOS_RD_BREQ,MOS_RD_BMREQ,reg_index,data,length);
return status;
}

// Set vendor specific command
Static int setVendorCommand(struct mos_softc *sc,u_int16_t reg_index,u_int16_t length,u_int8_t * data)
{
int status=0;
status=mos_cmd(sc,MOS_WR_BREQ,MOS_WR_BMREQ,reg_index,data,length);
return status;
}

Static int mos_initialize_device(struct mos_softc *sc)
{
	u_int8_t READ_HIF_REG_22;
	u_int8_t SByte;
	u_int8_t ptrPauseThreshold =0;
	u_int16_t	PhyAutoNegAdvReg;
	u_int16_t	PhyIDReg1=0;
	u_int16_t	PhyIDReg2=0;
	u_int16_t	tPhyIDReg=0;

	int status;
	int cnt=0;
	do
	{
	status=getVendorCommand(sc,HIF_REG_16,1,&READ_HIF_REG_22);
	dprintf(" status value of revision:%d\n",status);
	if(!status)
	{
		dprintf("Device is of revision C \n");
		sc->mos_devicerelnum=DEVICE_REV_C;
		break;
	}
	//DELAY(100);
	cnt++;
	}while(cnt > 2);
	cnt = 5;
	status=getVendorCommand(sc,HIF_REG_16,ETHER_ADDR_LEN,(u_int8_t *)&sc->eaddr);
	if(status)
	{
		printf("mac address failed to get\n");
	}
	else
	{
		printf(" Mac address:");
		for(cnt=0;cnt<ETHER_ADDR_LEN;cnt++)
		printf("%x:",sc->eaddr[cnt]);
		printf("\n");
		
	}

	status = mos_rwPHYRegPassive(sc,PHY_IDENTIFICATION1_REG_INDEX,&PhyIDReg1,READ_OPCODE);	
	if(status==0)
		dprintf("ReadPHYRegisterPassive for identification1 success\n");
	status = mos_rwPHYRegPassive(sc,PHY_IDENTIFICATION2_REG_INDEX,&PhyIDReg2,READ_OPCODE);	
	if(status==0)
		dprintf("ReadPHYRegisterPassive for identification2 success\n");

	if((PhyIDReg1 == INTEL_PHY_ID1) && (PhyIDReg2 == INTEL_PHY_ID2))
	{
		dprintf("INTEL PHY detected\n");
		tPhyIDReg=0x0080;
		mos_rwPHYRegPassive(sc,PHY_CONFIG_REG_INDEX,&tPhyIDReg,WRITE_OPCODE);	
	}
	else
	{
		dprintf(" FARADY PHY detected\n");
	}



	status = mos_rwPHYRegPassive(sc,PHY_AUTONEGADVT_REG_INDEX,&PhyAutoNegAdvReg,READ_OPCODE);	
	if(status==0)
		dprintf("ReadPHYRegisterPassive success\n");
	else
	{
		dprintf("ReadPHYRegisterPassive failed\n");
		return -1;
	}
	status = autoNegChangeMode(sc,0);
	if(status == 0)
		dprintf("Auto Negotation started\n");
	dprintf(" HIF_REG_15 value:%08x\n",sc->HIF_REG_15_val);	
	sc->HIF_REG_15_val |= (HIF_REG_15_TXENABLE| HIF_REG_15_RXENABLE);
	sc->HIF_REG_15_val |=  HIF_REG_15_ALLMULTICAST;
	dprintf(" Setting value of HIF_REG_15:%08x\n",sc->HIF_REG_15_val);
	status = 0;
	status = setVendorCommand(sc,HIF_REG_15,1,&sc->HIF_REG_15_val);
	if(status == 0)
		dprintf(" Moschip USB Start Device and Update HIF_REG_15 sucess\n");
	else
	{
		dprintf(" Moschip USB Start Device Failed !!!!!!!!\n");
		return -1;
	}

	//Only if we are in 10 Half mode
	if((!(sc->HIF_REG_15_val & HIF_REG_15_FULLDUPLEX_ENABLE)) && (!(sc->HIF_REG_15_val & HIF_REG_15_SPEED_100)) )
	{
		// Set 40 in HIF register 9
                SByte = 40;
                setVendorCommand(sc,HIF_REG_09,1,&SByte);


                // Set 32 in HIF register 10
                SByte = 32;
                setVendorCommand(sc,HIF_REG_10,1,&SByte);
	}
	ptrPauseThreshold = PTR_PAUSE_THRESHOLD;
	if(sc->mos_devicerelnum == DEVICE_REV_C)
	{
		dprintf(" !! Pause Threshold :%d\n",ptrPauseThreshold);
		status = setVendorCommand(sc,HIF_REG_23,1,&ptrPauseThreshold);
	}
	return status;

}
Static int mos_rwPHYRegPassive(struct mos_softc *sc,u_int8_t phyRegIndex,u_int16_t *phyRegValue,u_int8_t Opcode)
{
	int status=0;
	u_int8_t checkval=0;
	int count=0;
	//u_int16_t tRegValue=0;
//	dprintf(" opcode:%08x\n",Opcode);
	if(Opcode == READ_OPCODE)	
	status=setVendorCommand(sc,HIF_REG_11,1,&checkval);
	else
	{
	status=setVendorCommand(sc,HIF_REG_11,2,(u_int8_t *)phyRegValue);
	}

	if(status)
		return status;
	checkval= Opcode | FARADAY_PHY_ADDRESS;
	status=setVendorCommand(sc,HIF_REG_13,1,&checkval);
	if(status)
		return status;
	checkval = HIF_REG_14_PEND_FLAG_BIT | (phyRegIndex & 0x1f);
	status=setVendorCommand(sc,HIF_REG_14,1,&checkval);
	if(status)
		return status;
	count=10;
	do
	{
		status=0;
		checkval=0;
		status=getVendorCommand(sc,HIF_REG_14,1,&checkval);
		if(status)
			break;
		if(checkval & HIF_REG_14_READY_FLAG_BIT)
			break;
		else
		{
			count--;
			if(count==0)
			{
				status=-1;
				break;
			}
		}
			
	}while(1);
	if(status<0)
		return status;
	if(Opcode == READ_OPCODE)	
	{
	status=0;
	status=getVendorCommand(sc,HIF_REG_11,2,(u_int8_t *)phyRegValue);
	if(status<0)
		return status;
	}
	return status;
	
}
Static int autoNegChangeMode(struct mos_softc *sc,int mode)
{
	u_int8_t readHIFval=0;
	u_int16_t autoNegAdvtReg=0;
	u_int16_t phyControlReg=0;
	u_int16_t tphyControlReg=0;
	int status=0;
	if(mode == 0)
	{
		autoNegAdvtReg = PHY_AUTONEGADVT_FdxPause | PHY_AUTONEGADVT_Fdx100TX | PHY_AUTONEGADVT_100TX | PHY_AUTONEGADVT_ieee802_3 |  PHY_AUTONEGADVT_10TFdx | PHY_AUTONEGADVT_10T;
	}
	else if(mode == 1)	//10 Half duplex
	{
		autoNegAdvtReg = PHY_AUTONEGADVT_10T | PHY_AUTONEGADVT_ieee802_3;
	}
	else if(mode == 2)	// 10 Full duplex
	{
		autoNegAdvtReg = PHY_AUTONEGADVT_FdxPause | PHY_AUTONEGADVT_10TFdx | PHY_AUTONEGADVT_10T | PHY_AUTONEGADVT_ieee802_3;
		sc->HIF_REG_15_val |= HIF_REG_15_FULLDUPLEX_ENABLE;
	}
	else if(mode == 3)	//100 Half duplex
	{
		autoNegAdvtReg = PHY_AUTONEGADVT_100TX | PHY_AUTONEGADVT_ieee802_3;
		sc->HIF_REG_15_val |= HIF_REG_15_SPEED_100;
	}
	else if(mode == 4)	// 100 Full duplex
	{
		autoNegAdvtReg = PHY_AUTONEGADVT_FdxPause | PHY_AUTONEGADVT_Fdx100TX | PHY_AUTONEGADVT_100TX | PHY_AUTONEGADVT_ieee802_3;
		sc->HIF_REG_15_val |= (HIF_REG_15_SPEED_100 | HIF_REG_15_FULLDUPLEX_ENABLE);
	}

	status=mos_rwPHYRegPassive(sc,PHY_AUTONEGADVT_REG_INDEX,&autoNegAdvtReg,WRITE_OPCODE);
	if(status < 0)
		return -1;

	status=0;
	status=mos_rwPHYRegPassive(sc,PHY_CONTROL_REG_INDEX,&phyControlReg,WRITE_OPCODE);
	if(status < 0)
		return -1;
	phyControlReg= PHY_CONTROL_AUTONEG_ENABLE;

	status=0;
	status=mos_rwPHYRegPassive(sc,PHY_CONTROL_REG_INDEX,&phyControlReg,WRITE_OPCODE);
	if(status < 0)
		return -1;

	phyControlReg= PHY_CONTROL_AUTONEG_ENABLE | PHY_CONTROL_RESTART_AUTONEG;

	status=0;
	status=mos_rwPHYRegPassive(sc,PHY_CONTROL_REG_INDEX,&phyControlReg,WRITE_OPCODE);
	if(status < 0)
		return -1;

	status=0;
	status=mos_rwPHYRegPassive(sc,PHY_CONTROL_REG_INDEX,&tphyControlReg,READ_OPCODE);
	//dprintf(" tphycontrolReg:%08x\n",tphyControlReg);
	if(status < 0)
		return -1;

	status=0;
	status=mos_rwPHYRegPassive(sc,PHY_AUTONEGADVT_REG_INDEX,&autoNegAdvtReg,READ_OPCODE);
	if(status < 0)
		return -1;
	//dprintf(" autoNegAdvtReg:%08x\n",autoNegAdvtReg);
	//sc->HIF_REG_15_val |= HIF_REG_15_CFG;
#ifdef xyz
	if(autoNegAdvtReg & PHY_AUTONEGADVT_100TX)
		sc->HIF_REG_15_val |= HIF_REG_15_SPEED_100;
	else
		sc->HIF_REG_15_val &= ~HIF_REG_15_SPEED_100;

	if((autoNegAdvtReg & PHY_AUTONEGADVT_10TFdx)||(autoNegAdvtReg & PHY_AUTONEGADVT_Fdx100TX))
		sc->HIF_REG_15_val |= HIF_REG_15_FULLDUPLEX_ENABLE;
	else
		sc->HIF_REG_15_val &= ~HIF_REG_15_FULLDUPLEX_ENABLE; 
#endif

	status = 0;
	status = setVendorCommand(sc,HIF_REG_15,1,&sc->HIF_REG_15_val);
	if(status < 0)
		return -1;

	status = 0;
	status = getVendorCommand(sc,HIF_REG_15,1,&readHIFval);
	if(status < 0)
		return -1;
	return status;
}

Static int
mos_detach(device_ptr_t dev)
{
	struct mos_softc	*sc;
	struct ifnet		*ifp;
	dprintf("\n");
	sc = device_get_softc(dev);
	MOS_LOCK(sc);
	ifp = sc->mos_ifp;
	sc->mos_dying = 1;
#ifdef abcd
	untimeout(mos_tick, sc, sc->mos_stat_ch);
#endif
	ether_ifdetach(ifp);
        if_free(ifp);


	if (sc->mos_ep[MOS_ENDPT_TX] != NULL)
		usbd_abort_pipe(sc->mos_ep[MOS_ENDPT_TX]);
	if (sc->mos_ep[MOS_ENDPT_RX] != NULL)
		usbd_abort_pipe(sc->mos_ep[MOS_ENDPT_RX]);
	if (sc->mos_ep[MOS_ENDPT_INTR] != NULL)
		usbd_abort_pipe(sc->mos_ep[MOS_ENDPT_INTR]);
	
	MOS_UNLOCK(sc);
        mtx_destroy(&sc->mos_mtx);

	return(0);
}
Static void
mos_stop(struct mos_softc *sc)
{
	usbd_status		err;
	struct ifnet		*ifp;


	dprintf("\n");
	ifp = sc->mos_ifp;
	ifp->if_timer = 0;
#ifdef abcd
	untimeout(mos_tick, sc, sc->mos_stat_ch);
#endif

	/* Stop transfers. */
	if (sc->mos_ep[MOS_ENDPT_RX] != NULL) {
		err = usbd_abort_pipe(sc->mos_ep[MOS_ENDPT_RX]);
		if (err) {
			printf("mos%d: abort rx pipe failed: %s\n",
		    	sc->mos_unit, usbd_errstr(err));
		}
		err = usbd_close_pipe(sc->mos_ep[MOS_ENDPT_RX]);
		if (err) {
			printf("mos%d: close rx pipe failed: %s\n",
		    	sc->mos_unit, usbd_errstr(err));
		}
		sc->mos_ep[MOS_ENDPT_RX] = NULL;
	}

	if (sc->mos_ep[MOS_ENDPT_TX] != NULL) {
		err = usbd_abort_pipe(sc->mos_ep[MOS_ENDPT_TX]);
		if (err) {
			printf("mos%d: abort tx pipe failed: %s\n",
		    	sc->mos_unit, usbd_errstr(err));
		}
		err = usbd_close_pipe(sc->mos_ep[MOS_ENDPT_TX]);
		if (err) {
			printf("mos%d: close tx pipe failed: %s\n",
			    sc->mos_unit, usbd_errstr(err));
		}
		sc->mos_ep[MOS_ENDPT_TX] = NULL;
	}

	if (sc->mos_ep[MOS_ENDPT_INTR] != NULL) {
		err = usbd_abort_pipe(sc->mos_ep[MOS_ENDPT_INTR]);
		if (err) {
			printf("mos%d: abort intr pipe failed: %s\n",
		    	sc->mos_unit, usbd_errstr(err));
		}
		err = usbd_close_pipe(sc->mos_ep[MOS_ENDPT_INTR]);
		if (err) {
			printf("mos%d: close intr pipe failed: %s\n",
			    sc->mos_unit, usbd_errstr(err));
		}
		sc->mos_ep[MOS_ENDPT_INTR] = NULL;
	}

	mos_reset(sc);

	/* Free RX resources. */
	usb_ether_rx_list_free(&sc->mos_cdata);
	/* Free TX resources. */
	usb_ether_tx_list_free(&sc->mos_cdata);
	/* zero uchain uninitialise */
	usb_ether_tx_list_free(&sc->mos_zcdata);

	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
        sc->mos_link = 0;

	return;
}

/*
 * Stop all chip I/O so that the kernel's probe routines don't
 * get confused by errant DMAs when rebooting.
 */
Static void
mos_shutdown(device_ptr_t dev)
{
	struct mos_softc	*sc;

	dprintf("\n");
	sc = device_get_softc(dev);

	mos_stop(sc);

	return;
}
