Home | History | Annotate | Line # | Download | only in ic
dm9000.c revision 1.30
      1  1.30    andvar /*	$NetBSD: dm9000.c,v 1.30 2021/09/11 20:28:06 andvar Exp $	*/
      2   1.1     ahoka 
      3   1.1     ahoka /*
      4   1.1     ahoka  * Copyright (c) 2009 Paul Fleischer
      5   1.1     ahoka  * All rights reserved.
      6   1.1     ahoka  *
      7   1.1     ahoka  * 1. Redistributions of source code must retain the above copyright
      8   1.1     ahoka  *    notice, this list of conditions and the following disclaimer.
      9   1.1     ahoka  * 2. Redistributions in binary form must reproduce the above copyright
     10   1.1     ahoka  *    notice, this list of conditions and the following disclaimer in the
     11   1.1     ahoka  *    documentation and/or other materials provided with the distribution.
     12   1.1     ahoka  * 3. The name of the company nor the name of the author may be used to
     13   1.1     ahoka  *    endorse or promote products derived from this software without specific
     14   1.1     ahoka  *    prior written permission.
     15   1.1     ahoka  *
     16   1.1     ahoka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
     17   1.1     ahoka  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     18   1.1     ahoka  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19   1.1     ahoka  * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
     20   1.1     ahoka  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     21   1.1     ahoka  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     22   1.1     ahoka  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23   1.1     ahoka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24   1.1     ahoka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25   1.1     ahoka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26   1.1     ahoka  * SUCH DAMAGE.
     27   1.1     ahoka  */
     28   1.1     ahoka 
     29   1.1     ahoka /* based on sys/dev/ic/cs89x0.c */
     30   1.1     ahoka /*
     31   1.1     ahoka  * Copyright (c) 2004 Christopher Gilbert
     32   1.1     ahoka  * All rights reserved.
     33   1.1     ahoka  *
     34   1.1     ahoka  * 1. Redistributions of source code must retain the above copyright
     35   1.1     ahoka  *    notice, this list of conditions and the following disclaimer.
     36   1.1     ahoka  * 2. Redistributions in binary form must reproduce the above copyright
     37   1.1     ahoka  *    notice, this list of conditions and the following disclaimer in the
     38   1.1     ahoka  *    documentation and/or other materials provided with the distribution.
     39   1.1     ahoka  * 3. The name of the company nor the name of the author may be used to
     40   1.1     ahoka  *    endorse or promote products derived from this software without specific
     41   1.1     ahoka  *    prior written permission.
     42   1.1     ahoka  *
     43   1.1     ahoka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
     44   1.1     ahoka  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     45   1.1     ahoka  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     46   1.1     ahoka  * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
     47   1.1     ahoka  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     48   1.1     ahoka  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     49   1.1     ahoka  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     50   1.1     ahoka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     51   1.1     ahoka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     52   1.1     ahoka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     53   1.1     ahoka  * SUCH DAMAGE.
     54   1.1     ahoka  */
     55   1.1     ahoka 
     56   1.1     ahoka /*
     57   1.1     ahoka  * Copyright 1997
     58   1.1     ahoka  * Digital Equipment Corporation. All rights reserved.
     59   1.1     ahoka  *
     60   1.1     ahoka  * This software is furnished under license and may be used and
     61   1.1     ahoka  * copied only in accordance with the following terms and conditions.
     62   1.1     ahoka  * Subject to these conditions, you may download, copy, install,
     63   1.1     ahoka  * use, modify and distribute this software in source and/or binary
     64   1.1     ahoka  * form. No title or ownership is transferred hereby.
     65   1.1     ahoka  *
     66   1.1     ahoka  * 1) Any source code used, modified or distributed must reproduce
     67   1.1     ahoka  *    and retain this copyright notice and list of conditions as
     68   1.1     ahoka  *    they appear in the source file.
     69   1.1     ahoka  *
     70   1.1     ahoka  * 2) No right is granted to use any trade name, trademark, or logo of
     71   1.1     ahoka  *    Digital Equipment Corporation. Neither the "Digital Equipment
     72   1.1     ahoka  *    Corporation" name nor any trademark or logo of Digital Equipment
     73   1.1     ahoka  *    Corporation may be used to endorse or promote products derived
     74   1.1     ahoka  *    from this software without the prior written permission of
     75   1.1     ahoka  *    Digital Equipment Corporation.
     76   1.1     ahoka  *
     77   1.1     ahoka  * 3) This software is provided "AS-IS" and any express or implied
     78   1.1     ahoka  *    warranties, including but not limited to, any implied warranties
     79   1.1     ahoka  *    of merchantability, fitness for a particular purpose, or
     80   1.1     ahoka  *    non-infringement are disclaimed. In no event shall DIGITAL be
     81   1.1     ahoka  *    liable for any damages whatsoever, and in particular, DIGITAL
     82   1.1     ahoka  *    shall not be liable for special, indirect, consequential, or
     83   1.1     ahoka  *    incidental damages or damages for lost profits, loss of
     84   1.1     ahoka  *    revenue or loss of use, whether such damages arise in contract,
     85   1.1     ahoka  *    negligence, tort, under statute, in equity, at law or otherwise,
     86   1.1     ahoka  *    even if advised of the possibility of such damage.
     87   1.1     ahoka  */
     88   1.1     ahoka 
     89   1.1     ahoka #include <sys/cdefs.h>
     90   1.1     ahoka 
     91   1.1     ahoka #include <sys/param.h>
     92  1.24  nisimura #include <sys/bus.h>
     93  1.24  nisimura #include <sys/intr.h>
     94  1.24  nisimura #include <sys/device.h>
     95   1.1     ahoka #include <sys/mbuf.h>
     96  1.24  nisimura #include <sys/sockio.h>
     97   1.1     ahoka #include <sys/malloc.h>
     98   1.1     ahoka #include <sys/errno.h>
     99  1.24  nisimura #include <sys/cprng.h>
    100  1.24  nisimura #include <sys/rndsource.h>
    101  1.24  nisimura #include <sys/kernel.h>
    102  1.24  nisimura #include <sys/systm.h>
    103   1.1     ahoka 
    104   1.1     ahoka #include <net/if.h>
    105  1.24  nisimura #include <net/if_dl.h>
    106   1.1     ahoka #include <net/if_ether.h>
    107   1.1     ahoka #include <net/if_media.h>
    108  1.24  nisimura #include <dev/mii/mii.h>
    109  1.24  nisimura #include <dev/mii/miivar.h>
    110  1.13   msaitoh #include <net/bpf.h>
    111  1.13   msaitoh 
    112   1.1     ahoka #include <dev/ic/dm9000var.h>
    113   1.1     ahoka #include <dev/ic/dm9000reg.h>
    114   1.1     ahoka 
    115   1.1     ahoka #if 1
    116   1.1     ahoka #undef DM9000_DEBUG
    117   1.4  nisimura #undef DM9000_TX_DEBUG
    118   1.1     ahoka #undef DM9000_TX_DATA_DEBUG
    119   1.1     ahoka #undef DM9000_RX_DEBUG
    120   1.1     ahoka #undef  DM9000_RX_DATA_DEBUG
    121   1.1     ahoka #else
    122   1.1     ahoka #define DM9000_DEBUG
    123   1.1     ahoka #define  DM9000_TX_DEBUG
    124   1.1     ahoka #define DM9000_TX_DATA_DEBUG
    125   1.1     ahoka #define DM9000_RX_DEBUG
    126   1.1     ahoka #define  DM9000_RX_DATA_DEBUG
    127   1.1     ahoka #endif
    128   1.1     ahoka 
    129   1.1     ahoka #ifdef DM9000_DEBUG
    130   1.1     ahoka #define DPRINTF(s) do {printf s; } while (/*CONSTCOND*/0)
    131   1.1     ahoka #else
    132   1.1     ahoka #define DPRINTF(s) do {} while (/*CONSTCOND*/0)
    133   1.1     ahoka #endif
    134   1.1     ahoka 
    135   1.1     ahoka #ifdef DM9000_TX_DEBUG
    136   1.1     ahoka #define TX_DPRINTF(s) do {printf s; } while (/*CONSTCOND*/0)
    137   1.1     ahoka #else
    138   1.1     ahoka #define TX_DPRINTF(s) do {} while (/*CONSTCOND*/0)
    139   1.1     ahoka #endif
    140   1.1     ahoka 
    141   1.1     ahoka #ifdef DM9000_RX_DEBUG
    142   1.1     ahoka #define RX_DPRINTF(s) do {printf s; } while (/*CONSTCOND*/0)
    143   1.1     ahoka #else
    144   1.1     ahoka #define RX_DPRINTF(s) do {} while (/*CONSTCOND*/0)
    145   1.1     ahoka #endif
    146   1.1     ahoka 
    147   1.1     ahoka #ifdef DM9000_RX_DATA_DEBUG
    148   1.1     ahoka #define RX_DATA_DPRINTF(s) do {printf s; } while (/*CONSTCOND*/0)
    149   1.1     ahoka #else
    150   1.1     ahoka #define RX_DATA_DPRINTF(s) do {} while (/*CONSTCOND*/0)
    151   1.1     ahoka #endif
    152   1.1     ahoka 
    153   1.1     ahoka #ifdef DM9000_TX_DATA_DEBUG
    154   1.1     ahoka #define TX_DATA_DPRINTF(s) do {printf s; } while (/*CONSTCOND*/0)
    155   1.1     ahoka #else
    156   1.1     ahoka #define TX_DATA_DPRINTF(s) do {} while (/*CONSTCOND*/0)
    157   1.1     ahoka #endif
    158   1.1     ahoka 
    159  1.24  nisimura static void dme_reset(struct dme_softc *);
    160  1.24  nisimura static int dme_init(struct ifnet *);
    161  1.24  nisimura static void dme_stop(struct ifnet *, int);
    162  1.24  nisimura static void dme_start(struct ifnet *);
    163  1.24  nisimura static int dme_ioctl(struct ifnet *, u_long, void *);
    164  1.24  nisimura 
    165  1.24  nisimura static void dme_set_rcvfilt(struct dme_softc *);
    166  1.24  nisimura static void mii_statchg(struct ifnet *);
    167  1.24  nisimura static void lnkchg(struct dme_softc *);
    168  1.24  nisimura static void phy_tick(void *);
    169  1.24  nisimura static int mii_readreg(device_t, int, int, uint16_t *);
    170  1.24  nisimura static int mii_writereg(device_t, int, int, uint16_t);
    171  1.24  nisimura 
    172  1.24  nisimura static void dme_prepare(struct ifnet *);
    173  1.24  nisimura static void dme_transmit(struct ifnet *);
    174  1.24  nisimura static void dme_receive(struct ifnet *);
    175  1.24  nisimura 
    176  1.24  nisimura static int pkt_read_2(struct dme_softc *, struct mbuf **);
    177  1.24  nisimura static int pkt_write_2(struct dme_softc *, struct mbuf *);
    178  1.24  nisimura static int pkt_read_1(struct dme_softc *, struct mbuf **);
    179  1.24  nisimura static int pkt_write_1(struct dme_softc *, struct mbuf *);
    180  1.24  nisimura #define PKT_READ(ii,m) (*(ii)->sc_pkt_read)((ii),(m))
    181  1.24  nisimura #define PKT_WRITE(ii,m) (*(ii)->sc_pkt_write)((ii),(m))
    182  1.24  nisimura 
    183  1.24  nisimura #define ETHER_IS_ONE(x) \
    184  1.24  nisimura 	   (((x)[0] & (x)[1] & (x)[2] & (x)[3] & (x)[4] & (x)[5]) == 255)
    185  1.24  nisimura #define ETHER_IS_ZERO(x) \
    186  1.24  nisimura 	   (((x)[0] | (x)[1] | (x)[2] | (x)[3] | (x)[4] | (x)[5]) == 0)
    187   1.4  nisimura 
    188   1.4  nisimura int
    189  1.24  nisimura dme_attach(struct dme_softc *sc, const uint8_t *notusedanymore)
    190   1.4  nisimura {
    191  1.24  nisimura 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
    192  1.24  nisimura 	struct mii_data *mii = &sc->sc_mii;
    193  1.24  nisimura 	struct ifmedia *ifm = &mii->mii_media;
    194  1.24  nisimura 	uint8_t b[2];
    195  1.24  nisimura 	uint16_t io_mode;
    196  1.24  nisimura 	uint8_t enaddr[ETHER_ADDR_LEN];
    197  1.24  nisimura 	prop_dictionary_t dict;
    198  1.24  nisimura 	prop_data_t ea;
    199   1.1     ahoka 
    200   1.1     ahoka 	dme_read_c(sc, DM9000_VID0, b, 2);
    201  1.24  nisimura 	sc->sc_vendor_id = le16toh((uint16_t)b[1] << 8 | b[0]);
    202   1.1     ahoka 	dme_read_c(sc, DM9000_PID0, b, 2);
    203  1.24  nisimura 	sc->sc_product_id = le16toh((uint16_t)b[1] << 8 | b[0]);
    204  1.24  nisimura 
    205   1.1     ahoka 	/* TODO: Check the vendor ID as well */
    206   1.1     ahoka 	if (sc->sc_product_id != 0x9000) {
    207   1.1     ahoka 		panic("dme_attach: product id mismatch (0x%hx != 0x9000)",
    208   1.1     ahoka 		    sc->sc_product_id);
    209   1.1     ahoka 	}
    210  1.24  nisimura #if 1 || DM9000_DEBUG
    211  1.24  nisimura 	{
    212  1.24  nisimura 		dme_read_c(sc, DM9000_PAB0, enaddr, 6);
    213  1.24  nisimura 		aprint_normal_dev(sc->sc_dev,
    214  1.24  nisimura 		    "DM9000 was configured with MAC address: %s\n",
    215  1.24  nisimura 		    ether_sprintf(enaddr));
    216  1.24  nisimura 	}
    217  1.24  nisimura #endif
    218  1.24  nisimura 	dict = device_properties(sc->sc_dev);
    219  1.24  nisimura 	ea = (dict) ? prop_dictionary_get(dict, "mac-address") : NULL;
    220  1.24  nisimura 	if (ea != NULL) {
    221  1.24  nisimura 	       /*
    222  1.30    andvar 		 * If the MAC address is overridden by a device property,
    223  1.24  nisimura 		 * use that.
    224  1.24  nisimura 		 */
    225  1.24  nisimura 		KASSERT(prop_object_type(ea) == PROP_TYPE_DATA);
    226  1.24  nisimura 		KASSERT(prop_data_size(ea) == ETHER_ADDR_LEN);
    227  1.29  jmcneill 		memcpy(enaddr, prop_data_value(ea), ETHER_ADDR_LEN);
    228  1.28  nisimura 		aprint_debug_dev(sc->sc_dev, "got MAC address!\n");
    229  1.24  nisimura 	} else {
    230  1.24  nisimura 		/*
    231  1.24  nisimura 		 * If we did not get an externaly configure address,
    232  1.24  nisimura 		 * try to read one from the current setup, before
    233  1.24  nisimura 		 * resetting the chip.
    234  1.24  nisimura 		 */
    235  1.24  nisimura 		dme_read_c(sc, DM9000_PAB0, enaddr, 6);
    236  1.24  nisimura 		if (ETHER_IS_ONE(enaddr) || ETHER_IS_ZERO(enaddr)) {
    237  1.24  nisimura 			/* make a random MAC address */
    238  1.24  nisimura 			uint32_t maclo = 0x00f2 | (cprng_strong32() << 16);
    239  1.24  nisimura 			uint32_t machi = cprng_strong32();
    240  1.24  nisimura 			enaddr[0] = maclo;
    241  1.24  nisimura 			enaddr[1] = maclo >> 8;
    242  1.24  nisimura 			enaddr[2] = maclo >> 16;
    243  1.24  nisimura 			enaddr[3] = maclo >> 26;
    244  1.24  nisimura 			enaddr[4] = machi;
    245  1.24  nisimura 			enaddr[5] = machi >> 8;
    246  1.24  nisimura 		}
    247  1.24  nisimura 	}
    248  1.24  nisimura 	/* TODO: perform explicit EEPROM read op if it's availble */
    249  1.24  nisimura 
    250  1.24  nisimura 	dme_reset(sc);
    251  1.24  nisimura 
    252  1.24  nisimura 	mii->mii_ifp = ifp;
    253  1.24  nisimura 	mii->mii_readreg = mii_readreg;
    254  1.24  nisimura 	mii->mii_writereg = mii_writereg;
    255  1.24  nisimura 	mii->mii_statchg = mii_statchg;
    256  1.24  nisimura 
    257  1.25  nisimura 	/* assume davicom PHY at 1. ext PHY could be hooked but only at 0-3 */
    258  1.24  nisimura 	sc->sc_ethercom.ec_mii = mii;
    259  1.24  nisimura 	ifmedia_init(ifm, 0, ether_mediachange, ether_mediastatus);
    260  1.25  nisimura 	mii_attach(sc->sc_dev, mii, 0xffffffff, 1 /* PHY 1 */,
    261  1.25  nisimura 		MII_OFFSET_ANY, 0);
    262  1.24  nisimura 	if (LIST_FIRST(&mii->mii_phys) == NULL) {
    263  1.24  nisimura 		ifmedia_add(ifm, IFM_ETHER | IFM_NONE, 0, NULL);
    264  1.24  nisimura 		ifmedia_set(ifm, IFM_ETHER | IFM_NONE);
    265  1.24  nisimura 	} else
    266  1.24  nisimura 		ifmedia_set(ifm, IFM_ETHER | IFM_AUTO);
    267  1.24  nisimura 	ifm->ifm_media = ifm->ifm_cur->ifm_media;
    268   1.1     ahoka 
    269   1.1     ahoka 	strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
    270   1.1     ahoka 	ifp->if_softc = sc;
    271  1.24  nisimura 	ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST;
    272   1.1     ahoka 	ifp->if_init = dme_init;
    273  1.24  nisimura 	ifp->if_start = dme_start;
    274  1.24  nisimura 	ifp->if_stop = dme_stop;
    275   1.1     ahoka 	ifp->if_ioctl = dme_ioctl;
    276  1.24  nisimura 	ifp->if_watchdog = NULL; /* no watchdog used */
    277  1.24  nisimura 	IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
    278   1.1     ahoka 	IFQ_SET_READY(&ifp->if_snd);
    279   1.1     ahoka 
    280  1.24  nisimura 	if_attach(ifp);
    281  1.24  nisimura 	ether_ifattach(ifp, enaddr);
    282  1.24  nisimura 	if_deferred_start_init(ifp, NULL);
    283  1.24  nisimura 
    284  1.24  nisimura 	rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev),
    285  1.24  nisimura             RND_TYPE_NET, RND_FLAG_DEFAULT);
    286   1.4  nisimura 
    287  1.24  nisimura 	/* might be unnecessary as link change interrupt works well */
    288   1.4  nisimura 	callout_init(&sc->sc_link_callout, 0);
    289  1.24  nisimura 	callout_setfunc(&sc->sc_link_callout, phy_tick, sc);
    290   1.1     ahoka 
    291   1.4  nisimura 	io_mode = (dme_read(sc, DM9000_ISR) &
    292   1.1     ahoka 	    DM9000_IOMODE_MASK) >> DM9000_IOMODE_SHIFT;
    293   1.4  nisimura 
    294  1.25  nisimura 	/* frame body read/write ops in 2 byte quantity or byte-wise. */
    295   1.4  nisimura 	DPRINTF(("DM9000 Operation Mode: "));
    296  1.18   msaitoh 	switch (io_mode) {
    297  1.24  nisimura 	case DM9000_MODE_8BIT:
    298  1.24  nisimura 		DPRINTF(("8-bit mode"));
    299  1.24  nisimura 		sc->sc_data_width = 1;
    300  1.24  nisimura 		sc->sc_pkt_write = pkt_write_1;
    301  1.24  nisimura 		sc->sc_pkt_read = pkt_read_1;
    302  1.24  nisimura 		break;
    303   1.1     ahoka 	case DM9000_MODE_16BIT:
    304   1.4  nisimura 		DPRINTF(("16-bit mode"));
    305   1.4  nisimura 		sc->sc_data_width = 2;
    306  1.24  nisimura 		sc->sc_pkt_write = pkt_write_2;
    307  1.24  nisimura 		sc->sc_pkt_read = pkt_read_2;
    308   1.1     ahoka 		break;
    309   1.1     ahoka 	case DM9000_MODE_32BIT:
    310   1.4  nisimura 		DPRINTF(("32-bit mode"));
    311   1.4  nisimura 		sc->sc_data_width = 4;
    312   1.6  macallan 		panic("32bit mode is unsupported\n");
    313   1.1     ahoka 		break;
    314   1.4  nisimura 	default:
    315   1.4  nisimura 		DPRINTF(("Invalid mode"));
    316   1.1     ahoka 		break;
    317   1.1     ahoka 	}
    318   1.4  nisimura 	DPRINTF(("\n"));
    319   1.4  nisimura 
    320  1.24  nisimura 	return 0;
    321  1.24  nisimura }
    322   1.1     ahoka 
    323  1.24  nisimura int
    324  1.24  nisimura dme_detach(struct dme_softc *sc)
    325  1.24  nisimura {
    326   1.1     ahoka 	return 0;
    327   1.1     ahoka }
    328   1.1     ahoka 
    329  1.24  nisimura /* Software Initialize/Reset of the DM9000 */
    330  1.24  nisimura static void
    331  1.24  nisimura dme_reset(struct dme_softc *sc)
    332   1.1     ahoka {
    333  1.24  nisimura 	uint8_t misc;
    334   1.1     ahoka 
    335  1.24  nisimura 	/* We only re-initialized the PHY in this function the first time it is
    336  1.24  nisimura 	 * called. */
    337  1.24  nisimura 	if (!sc->sc_phy_initialized) {
    338  1.24  nisimura 		/* PHY Reset */
    339  1.24  nisimura 		mii_writereg(sc->sc_dev, 1, MII_BMCR, BMCR_RESET);
    340   1.4  nisimura 
    341  1.24  nisimura 		/* PHY Power Down */
    342  1.24  nisimura 		misc = dme_read(sc, DM9000_GPR);
    343  1.24  nisimura 		dme_write(sc, DM9000_GPR, misc | DM9000_GPR_PHY_PWROFF);
    344   1.1     ahoka 	}
    345   1.1     ahoka 
    346  1.24  nisimura 	/* Reset the DM9000 twice, as described in section 2 of the Programming
    347  1.24  nisimura 	 * Guide.
    348  1.24  nisimura 	 * The PHY is initialized and enabled between those two resets.
    349  1.24  nisimura 	 */
    350   1.1     ahoka 
    351  1.24  nisimura 	/* Software Reset */
    352  1.24  nisimura 	dme_write(sc, DM9000_NCR,
    353  1.24  nisimura 	    DM9000_NCR_RST | DM9000_NCR_LBK_MAC_INTERNAL);
    354  1.24  nisimura 	delay(20);
    355  1.24  nisimura 	dme_write(sc, DM9000_NCR, 0x0);
    356   1.1     ahoka 
    357  1.24  nisimura 	if (!sc->sc_phy_initialized) {
    358  1.24  nisimura 		/* PHY Enable */
    359  1.24  nisimura 		misc = dme_read(sc, DM9000_GPR);
    360  1.24  nisimura 		dme_write(sc, DM9000_GPR, misc & ~DM9000_GPR_PHY_PWROFF);
    361  1.24  nisimura 		misc = dme_read(sc, DM9000_GPCR);
    362  1.24  nisimura 		dme_write(sc, DM9000_GPCR, misc | DM9000_GPCR_GPIO0_OUT);
    363   1.1     ahoka 
    364  1.24  nisimura 		dme_write(sc, DM9000_NCR,
    365  1.24  nisimura 		    DM9000_NCR_RST | DM9000_NCR_LBK_MAC_INTERNAL);
    366  1.24  nisimura 		delay(20);
    367  1.24  nisimura 		dme_write(sc, DM9000_NCR, 0x0);
    368  1.24  nisimura 	}
    369   1.1     ahoka 
    370  1.24  nisimura 	/* Select internal PHY, no wakeup event, no collosion mode,
    371  1.24  nisimura 	 * normal loopback mode.
    372  1.24  nisimura 	 */
    373  1.24  nisimura 	dme_write(sc, DM9000_NCR, DM9000_NCR_LBK_NORMAL);
    374   1.1     ahoka 
    375  1.24  nisimura 	/* Will clear TX1END, TX2END, and WAKEST fields by reading DM9000_NSR*/
    376  1.24  nisimura 	dme_read(sc, DM9000_NSR);
    377   1.1     ahoka 
    378  1.24  nisimura 	/* Enable wraparound of read/write pointer, frame received latch,
    379  1.24  nisimura 	 * and frame transmitted latch.
    380  1.24  nisimura 	 */
    381  1.17   msaitoh 	dme_write(sc, DM9000_IMR,
    382  1.17   msaitoh 	    DM9000_IMR_PAR | DM9000_IMR_PRM | DM9000_IMR_PTM);
    383   1.1     ahoka 
    384  1.24  nisimura 	dme_write(sc, DM9000_RCR,
    385  1.24  nisimura 	    DM9000_RCR_DIS_CRC | DM9000_RCR_DIS_LONG | DM9000_RCR_WTDIS);
    386   1.4  nisimura 
    387  1.24  nisimura 	sc->sc_phy_initialized = 1;
    388   1.1     ahoka }
    389   1.1     ahoka 
    390  1.24  nisimura static int
    391  1.24  nisimura dme_init(struct ifnet *ifp)
    392   1.1     ahoka {
    393  1.24  nisimura 	struct dme_softc *sc = ifp->if_softc;
    394   1.1     ahoka 
    395  1.24  nisimura 	dme_stop(ifp, 0);
    396  1.24  nisimura 	dme_reset(sc);
    397  1.24  nisimura 	dme_write_c(sc, DM9000_PAB0, CLLADDR(ifp->if_sadl), ETHER_ADDR_LEN);
    398  1.24  nisimura 	dme_set_rcvfilt(sc);
    399  1.24  nisimura 	(void)ether_mediachange(ifp);
    400  1.24  nisimura 
    401  1.24  nisimura 	sc->txbusy = sc->txready = 0;
    402  1.24  nisimura 
    403  1.24  nisimura 	ifp->if_flags |= IFF_RUNNING;
    404  1.24  nisimura 	ifp->if_flags &= ~IFF_OACTIVE;
    405  1.24  nisimura 	callout_schedule(&sc->sc_link_callout, hz);
    406   1.1     ahoka 
    407  1.24  nisimura 	return 0;
    408  1.24  nisimura }
    409   1.4  nisimura 
    410  1.24  nisimura /* Configure multicast filter */
    411  1.24  nisimura static void
    412  1.24  nisimura dme_set_rcvfilt(struct dme_softc *sc)
    413  1.24  nisimura {
    414  1.24  nisimura 	struct ethercom	*ec = &sc->sc_ethercom;
    415  1.24  nisimura 	struct ifnet *ifp = &ec->ec_if;
    416  1.24  nisimura 	struct ether_multi *enm;
    417  1.24  nisimura 	struct ether_multistep step;
    418  1.24  nisimura 	uint8_t mchash[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; /* 64bit mchash */
    419  1.24  nisimura 	uint32_t h = 0;
    420  1.24  nisimura 	int rcr;
    421   1.1     ahoka 
    422  1.24  nisimura 	rcr = dme_read(sc, DM9000_RCR);
    423  1.24  nisimura 	rcr &= ~(DM9000_RCR_PRMSC | DM9000_RCR_ALL);
    424  1.24  nisimura 	dme_write(sc, DM9000_RCR, rcr &~ DM9000_RCR_RXEN);
    425   1.1     ahoka 
    426  1.24  nisimura 	ETHER_LOCK(ec);
    427  1.24  nisimura 	if (ifp->if_flags & IFF_PROMISC) {
    428  1.24  nisimura 		ec->ec_flags |= ETHER_F_ALLMULTI;
    429  1.24  nisimura 		ETHER_UNLOCK(ec);
    430  1.24  nisimura 		/* run promisc. mode */
    431  1.24  nisimura 		rcr |= DM9000_RCR_PRMSC;
    432  1.24  nisimura 		goto update;
    433  1.24  nisimura 	}
    434  1.24  nisimura 	ec->ec_flags &= ~ETHER_F_ALLMULTI;
    435  1.24  nisimura 	ETHER_FIRST_MULTI(step, ec, enm);
    436  1.24  nisimura 	while (enm != NULL) {
    437  1.24  nisimura 		if (memcpy(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
    438  1.24  nisimura 			/*
    439  1.24  nisimura 			 * We must listen to a range of multicast addresses.
    440  1.24  nisimura 			 * For now, just accept all multicasts, rather than
    441  1.24  nisimura 			 * trying to set only those filter bits needed to match
    442  1.24  nisimura 			 * the range.  (At this time, the only use of address
    443  1.24  nisimura 			 * ranges is for IP multicast routing, for which the
    444  1.24  nisimura 			 * range is big enough to require all bits set.)
    445  1.24  nisimura 			 */
    446  1.24  nisimura 			ec->ec_flags |= ETHER_F_ALLMULTI;
    447  1.24  nisimura 			ETHER_UNLOCK(ec);
    448  1.24  nisimura 			memset(mchash, 0xff, sizeof(mchash)); /* necessary? */
    449  1.24  nisimura 			/* accept all mulicast frame */
    450  1.24  nisimura 			rcr |= DM9000_RCR_ALL;
    451  1.24  nisimura 			break;
    452  1.24  nisimura 		}
    453  1.24  nisimura 		h = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN) & 0x3f;
    454  1.24  nisimura 		/* 3(5:3) and 3(2:0) sampling to have uint8_t[8] */
    455  1.24  nisimura 		mchash[h / 8] |= 1 << (h % 8);
    456  1.24  nisimura 		ETHER_NEXT_MULTI(step, enm);
    457   1.1     ahoka 	}
    458  1.24  nisimura 	ETHER_UNLOCK(ec);
    459  1.24  nisimura 	/* DM9000 receive filter is always on */
    460  1.24  nisimura 	mchash[7] |= 0x80; /* to catch bcast frame */
    461  1.24  nisimura  update:
    462  1.24  nisimura 	dme_write_c(sc, DM9000_MAB0, mchash, sizeof(mchash));
    463  1.24  nisimura 	dme_write(sc, DM9000_RCR, rcr | DM9000_RCR_RXEN);
    464  1.24  nisimura 	return;
    465   1.1     ahoka }
    466   1.1     ahoka 
    467   1.1     ahoka void
    468  1.24  nisimura lnkchg(struct dme_softc *sc)
    469   1.1     ahoka {
    470  1.24  nisimura 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
    471  1.24  nisimura 	struct ifmediareq ifmr;
    472  1.24  nisimura 
    473  1.24  nisimura 	ether_mediastatus(ifp, &ifmr);
    474  1.24  nisimura }
    475   1.1     ahoka 
    476  1.24  nisimura static void
    477  1.24  nisimura mii_statchg(struct ifnet *ifp)
    478  1.24  nisimura {
    479  1.24  nisimura 	struct dme_softc *sc = ifp->if_softc;
    480  1.24  nisimura 	struct mii_data *mii = &sc->sc_mii;
    481  1.27     skrll 	uint8_t fcr, ncr;
    482  1.27     skrll 
    483  1.27     skrll #if 0
    484  1.24  nisimura 	const uint8_t Mbps[2] = { 10, 100 };
    485  1.27     skrll 	uint8_t nsr = dme_read(sc, DM9000_NSR);
    486  1.27     skrll 	int spd = Mbps[!!(nsr & DM9000_NSR_SPEED)];
    487  1.24  nisimura 	/* speed/duplexity available also in reg 0x11 of internal PHY */
    488  1.24  nisimura 	if (nsr & DM9000_NSR_LINKST)
    489  1.24  nisimura 		printf("link up,spd%d", spd);
    490  1.24  nisimura 	else
    491  1.24  nisimura 		printf("link down");
    492   1.1     ahoka 
    493  1.24  nisimura 	/* show resolved mii(4) parameters */
    494  1.24  nisimura 	printf("MII spd%d",
    495  1.24  nisimura 	    (int)(sc->sc_ethercom.ec_if.if_baudrate / IF_Mbps(1)));
    496  1.24  nisimura 	if (mii->mii_media_active & IFM_FDX)
    497  1.24  nisimura 		printf(",full-duplex");
    498  1.24  nisimura 	printf("\n");
    499  1.24  nisimura #endif
    500   1.1     ahoka 
    501  1.24  nisimura 	/* Adjust duplexity and PAUSE flow control. */
    502  1.24  nisimura 	fcr = dme_read(sc, DM9000_FCR) &~ DM9000_FCR_FLCE;
    503  1.24  nisimura 	ncr = dme_read(sc, DM9000_NCR) &~ DM9000_NCR_FDX;
    504  1.24  nisimura 	if ((mii->mii_media_active & IFM_FDX)
    505  1.24  nisimura 	    && (mii->mii_media_active & IFM_FLOW)) {
    506  1.24  nisimura 		fcr |= DM9000_FCR_FLCE;
    507  1.24  nisimura 		ncr |= DM9000_NCR_FDX;
    508   1.1     ahoka 	}
    509  1.24  nisimura 	dme_write(sc, DM9000_FCR, fcr);
    510  1.24  nisimura 	dme_write(sc, DM9000_NCR, ncr);
    511  1.24  nisimura }
    512   1.1     ahoka 
    513  1.24  nisimura static void
    514  1.24  nisimura phy_tick(void *arg)
    515  1.24  nisimura {
    516  1.24  nisimura 	struct dme_softc *sc = arg;
    517  1.24  nisimura 	struct mii_data *mii = &sc->sc_mii;
    518  1.24  nisimura 	int s;
    519   1.1     ahoka 
    520  1.24  nisimura 	s = splnet();
    521  1.24  nisimura 	mii_tick(mii);
    522  1.24  nisimura 	splx(s);
    523   1.1     ahoka 
    524  1.24  nisimura 	callout_schedule(&sc->sc_link_callout, hz);
    525  1.24  nisimura }
    526   1.1     ahoka 
    527  1.24  nisimura static int
    528  1.24  nisimura mii_readreg(device_t self, int phy, int reg, uint16_t *val)
    529  1.24  nisimura {
    530  1.24  nisimura 	struct dme_softc *sc = device_private(self);
    531   1.1     ahoka 
    532  1.24  nisimura 	if (phy != 1)
    533  1.24  nisimura 		return EINVAL;
    534   1.1     ahoka 
    535  1.24  nisimura 	/* Select Register to read*/
    536  1.24  nisimura 	dme_write(sc, DM9000_EPAR, DM9000_EPAR_INT_PHY +
    537  1.24  nisimura 	    (reg & DM9000_EPAR_EROA_MASK));
    538  1.24  nisimura 	/* Select read operation (DM9000_EPCR_ERPRR) from the PHY */
    539  1.24  nisimura 	dme_write(sc, DM9000_EPCR, DM9000_EPCR_ERPRR + DM9000_EPCR_EPOS_PHY);
    540   1.1     ahoka 
    541  1.24  nisimura 	/* Wait until access to PHY has completed */
    542  1.24  nisimura 	while (dme_read(sc, DM9000_EPCR) & DM9000_EPCR_ERRE)
    543  1.24  nisimura 		;
    544   1.1     ahoka 
    545  1.24  nisimura 	/* Reset ERPRR-bit */
    546  1.24  nisimura 	dme_write(sc, DM9000_EPCR, DM9000_EPCR_EPOS_PHY);
    547   1.1     ahoka 
    548  1.24  nisimura 	*val = dme_read(sc, DM9000_EPDRL) | (dme_read(sc, DM9000_EPDRH) << 8);
    549  1.24  nisimura 	return 0;
    550   1.1     ahoka }
    551   1.1     ahoka 
    552  1.24  nisimura static int
    553  1.24  nisimura mii_writereg(device_t self, int phy, int reg, uint16_t val)
    554   1.1     ahoka {
    555  1.24  nisimura 	struct dme_softc *sc = device_private(self);
    556   1.1     ahoka 
    557  1.24  nisimura 	if (phy != 1)
    558  1.24  nisimura 		return EINVAL;
    559   1.1     ahoka 
    560  1.24  nisimura 	/* Select Register to write */
    561  1.24  nisimura 	dme_write(sc, DM9000_EPAR, DM9000_EPAR_INT_PHY +
    562  1.24  nisimura 	    (reg & DM9000_EPAR_EROA_MASK));
    563   1.1     ahoka 
    564  1.24  nisimura 	/* Write data to the two data registers */
    565  1.24  nisimura 	dme_write(sc, DM9000_EPDRL, val & 0xFF);
    566  1.24  nisimura 	dme_write(sc, DM9000_EPDRH, (val >> 8) & 0xFF);
    567   1.1     ahoka 
    568  1.24  nisimura 	/* Select write operation (DM9000_EPCR_ERPRW) from the PHY */
    569  1.24  nisimura 	dme_write(sc, DM9000_EPCR, DM9000_EPCR_ERPRW + DM9000_EPCR_EPOS_PHY);
    570   1.1     ahoka 
    571  1.24  nisimura 	/* Wait until access to PHY has completed */
    572  1.24  nisimura 	while (dme_read(sc, DM9000_EPCR) & DM9000_EPCR_ERRE)
    573  1.24  nisimura 		;
    574   1.1     ahoka 
    575  1.24  nisimura 	/* Reset ERPRR-bit */
    576  1.24  nisimura 	dme_write(sc, DM9000_EPCR, DM9000_EPCR_EPOS_PHY);
    577   1.1     ahoka 
    578  1.24  nisimura 	return 0;
    579   1.1     ahoka }
    580   1.1     ahoka 
    581   1.1     ahoka void
    582   1.1     ahoka dme_stop(struct ifnet *ifp, int disable)
    583   1.1     ahoka {
    584   1.1     ahoka 	struct dme_softc *sc = ifp->if_softc;
    585   1.1     ahoka 
    586   1.1     ahoka 	/* Not quite sure what to do when called with disable == 0 */
    587   1.1     ahoka 	if (disable) {
    588   1.1     ahoka 		/* Disable RX */
    589   1.1     ahoka 		dme_write(sc, DM9000_RCR, 0x0);
    590   1.1     ahoka 	}
    591  1.24  nisimura 	mii_down(&sc->sc_mii);
    592  1.24  nisimura 	callout_stop(&sc->sc_link_callout);
    593   1.1     ahoka 
    594   1.1     ahoka 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
    595   1.1     ahoka 	ifp->if_timer = 0;
    596   1.1     ahoka }
    597   1.1     ahoka 
    598  1.24  nisimura static void
    599  1.24  nisimura dme_start(struct ifnet *ifp)
    600   1.1     ahoka {
    601   1.4  nisimura 	struct dme_softc *sc = ifp->if_softc;
    602   1.4  nisimura 
    603  1.24  nisimura 	if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) {
    604  1.24  nisimura 		printf("No output\n");
    605  1.24  nisimura 		return;
    606  1.24  nisimura 	}
    607  1.24  nisimura 	if (sc->txbusy && sc->txready)
    608  1.24  nisimura 		panic("DM9000: Internal error, trying to send without"
    609  1.24  nisimura 		    " any empty queue\n");
    610  1.24  nisimura 
    611  1.24  nisimura 	dme_prepare(ifp);
    612  1.24  nisimura 	if (sc->txbusy) {
    613  1.24  nisimura 		/* We need to wait until the current frame has
    614  1.24  nisimura 		 * been transmitted.
    615  1.24  nisimura 		 */
    616  1.24  nisimura 		ifp->if_flags |= IFF_OACTIVE;
    617  1.24  nisimura 		return;
    618  1.24  nisimura 	}
    619  1.24  nisimura 	/* We are ready to transmit right away */
    620  1.24  nisimura 	dme_transmit(ifp);
    621  1.24  nisimura 	dme_prepare(ifp); /* Prepare next one */
    622   1.1     ahoka }
    623   1.1     ahoka 
    624  1.24  nisimura /* Prepare data to be transmitted (i.e. dequeue and load it into the DM9000) */
    625  1.24  nisimura static void
    626  1.24  nisimura dme_prepare(struct ifnet *ifp)
    627   1.1     ahoka {
    628   1.1     ahoka 	struct dme_softc *sc = ifp->if_softc;
    629  1.24  nisimura 	uint16_t length;
    630  1.24  nisimura 	struct mbuf *m;
    631  1.24  nisimura 
    632  1.24  nisimura 	if (sc->txready)
    633  1.24  nisimura 		panic("dme_prepare: Someone called us with txready set\n");
    634  1.24  nisimura 
    635  1.24  nisimura 	IFQ_DEQUEUE(&ifp->if_snd, m);
    636  1.24  nisimura 	if (m == NULL) {
    637  1.24  nisimura 		TX_DPRINTF(("dme_prepare: Nothing to transmit\n"));
    638  1.24  nisimura 		ifp->if_flags &= ~IFF_OACTIVE; /* Clear OACTIVE bit */
    639  1.24  nisimura 		return; /* Nothing to transmit */
    640  1.24  nisimura 	}
    641  1.24  nisimura 
    642  1.24  nisimura 	/* Element has now been removed from the queue, so we better send it */
    643  1.24  nisimura 
    644  1.24  nisimura 	bpf_mtap(ifp, m, BPF_D_OUT);
    645  1.24  nisimura 
    646  1.24  nisimura 	/* Setup the DM9000 to accept the writes, and then write each buf in
    647  1.24  nisimura 	   the chain. */
    648  1.24  nisimura 
    649  1.24  nisimura 	TX_DATA_DPRINTF(("dme_prepare: Writing data: "));
    650  1.24  nisimura 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, sc->dme_io, DM9000_MWCMD);
    651  1.24  nisimura 	length = PKT_WRITE(sc, m);
    652  1.24  nisimura 	bpf_mtap(ifp, m, BPF_D_OUT);
    653  1.24  nisimura 	TX_DATA_DPRINTF(("\n"));
    654  1.24  nisimura 
    655  1.24  nisimura 	if (length % sc->sc_data_width != 0)
    656  1.24  nisimura 		panic("dme_prepare: length is not compatible with IO_MODE");
    657   1.1     ahoka 
    658  1.24  nisimura 	sc->txready_length = length;
    659  1.24  nisimura 	sc->txready = 1;
    660  1.24  nisimura 	m_freem(m);
    661   1.1     ahoka }
    662   1.1     ahoka 
    663  1.24  nisimura /* Transmit prepared data */
    664  1.24  nisimura static void
    665  1.24  nisimura dme_transmit(struct ifnet *ifp)
    666   1.1     ahoka {
    667  1.24  nisimura 	struct dme_softc *sc = ifp->if_softc;
    668   1.1     ahoka 
    669   1.1     ahoka 	TX_DPRINTF(("dme_transmit: PRE: txready: %d, txbusy: %d\n",
    670   1.1     ahoka 		sc->txready, sc->txbusy));
    671   1.1     ahoka 
    672  1.24  nisimura 	/* prime frame length first */
    673   1.1     ahoka 	dme_write(sc, DM9000_TXPLL, sc->txready_length & 0xff);
    674  1.24  nisimura 	dme_write(sc, DM9000_TXPLH, (sc->txready_length >> 8) & 0xff);
    675  1.24  nisimura 	/* read isr next */
    676   1.5     skrll 	dme_read(sc, DM9000_ISR);
    677  1.24  nisimura 	/* finally issue a request to send */
    678   1.1     ahoka 	dme_write(sc, DM9000_TCR, DM9000_TCR_TXREQ);
    679   1.1     ahoka 	sc->txready = 0;
    680   1.1     ahoka 	sc->txbusy = 1;
    681   1.1     ahoka 	sc->txready_length = 0;
    682   1.1     ahoka }
    683   1.1     ahoka 
    684  1.24  nisimura /* Receive data */
    685  1.24  nisimura static void
    686  1.24  nisimura dme_receive(struct ifnet *ifp)
    687   1.1     ahoka {
    688  1.24  nisimura 	struct dme_softc *sc = ifp->if_softc;
    689  1.24  nisimura 	struct mbuf *m;
    690  1.24  nisimura 	uint8_t avail, rsr;
    691   1.1     ahoka 
    692   1.1     ahoka 	DPRINTF(("inside dme_receive\n"));
    693   1.1     ahoka 
    694  1.24  nisimura 	/* frame has just arrived, retrieve it */
    695  1.24  nisimura 	/* called right after Rx frame available interrupt */
    696  1.24  nisimura 	do {
    697  1.24  nisimura 		/* "no increment" read to get the avail byte without
    698   1.7  macallan 		   moving past it. */
    699  1.24  nisimura 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, sc->dme_io,
    700  1.24  nisimura 			DM9000_MRCMDX);
    701  1.24  nisimura 		/* Read twice */
    702  1.24  nisimura 		avail = bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->dme_data);
    703  1.24  nisimura 		avail = bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->dme_data);
    704  1.24  nisimura 		avail &= 03;	/* 1:0 we only want these bits */
    705  1.24  nisimura 		if (avail == 01) {
    706   1.1     ahoka 			/* Read with address increment. */
    707  1.24  nisimura 			bus_space_write_1(sc->sc_iot, sc->sc_ioh, sc->dme_io,
    708  1.24  nisimura 				DM9000_MRCMD);
    709  1.24  nisimura 			rsr = PKT_READ(sc, &m);
    710   1.8  macallan 			if (m == NULL) {
    711   1.8  macallan 				/* failed to allocate a receive buffer */
    712   1.8  macallan 				RX_DPRINTF(("dme_receive: "
    713   1.8  macallan 					"Error allocating buffer\n"));
    714  1.24  nisimura 				if_statinc(ifp, if_ierrors);
    715  1.24  nisimura 				continue;
    716  1.24  nisimura 			}
    717  1.24  nisimura 			if (rsr & (DM9000_RSR_CE | DM9000_RSR_PLE)) {
    718  1.24  nisimura 				/* Error while receiving the frame,
    719   1.1     ahoka 				 * discard it and keep track of counters
    720   1.1     ahoka 				 */
    721  1.24  nisimura 				RX_DPRINTF(("dme_receive: "
    722  1.24  nisimura 					"Error reciving frame\n"));
    723  1.22   thorpej 				if_statinc(ifp, if_ierrors);
    724  1.24  nisimura 				continue;
    725  1.24  nisimura 			}
    726  1.24  nisimura 			if (rsr & DM9000_RSR_LCS) {
    727  1.22   thorpej 				if_statinc(ifp, if_collisions);
    728  1.24  nisimura 				continue;
    729   1.1     ahoka 			}
    730  1.26  nisimura 			/* pick and forward this frame to ifq */
    731  1.24  nisimura 			if_percpuq_enqueue(ifp->if_percpuq, m);
    732  1.24  nisimura 		} else if (avail != 00) {
    733   1.1     ahoka 			/* Should this be logged somehow? */
    734   1.4  nisimura 			printf("%s: Resetting chip\n",
    735   1.4  nisimura 			       device_xname(sc->sc_dev));
    736   1.1     ahoka 			dme_reset(sc);
    737  1.26  nisimura 			break;
    738   1.1     ahoka 		}
    739  1.26  nisimura 	} while (avail == 01);
    740  1.24  nisimura 	/* frame receieved successfully */
    741   1.1     ahoka }
    742   1.1     ahoka 
    743  1.24  nisimura int
    744  1.24  nisimura dme_intr(void *arg)
    745   1.1     ahoka {
    746  1.24  nisimura 	struct dme_softc *sc = arg;
    747  1.24  nisimura 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
    748  1.24  nisimura 	uint8_t isr, nsr, tsr;
    749  1.24  nisimura 
    750  1.24  nisimura 	DPRINTF(("dme_intr: Begin\n"));
    751  1.24  nisimura 
    752  1.24  nisimura 	/* Disable interrupts */
    753  1.24  nisimura 	dme_write(sc, DM9000_IMR, DM9000_IMR_PAR);
    754   1.1     ahoka 
    755  1.24  nisimura 	isr = dme_read(sc, DM9000_ISR);
    756  1.24  nisimura 	dme_write(sc, DM9000_ISR, isr); /* write to clear */
    757   1.4  nisimura 
    758  1.24  nisimura 	if (isr & DM9000_ISR_PRS) {
    759  1.24  nisimura 		KASSERT(ifp->if_flags & IFF_RUNNING);
    760  1.24  nisimura 		dme_receive(ifp);
    761   1.4  nisimura 	}
    762  1.24  nisimura 	if (isr & DM9000_ISR_LNKCHNG)
    763  1.24  nisimura 		lnkchg(sc);
    764  1.24  nisimura 	if (isr & DM9000_ISR_PTS) {
    765  1.24  nisimura 		tsr = 0x01; /* Initialize to an error value */
    766   1.1     ahoka 
    767  1.24  nisimura 		/* A frame has been transmitted */
    768  1.24  nisimura 		sc->txbusy = 0;
    769   1.4  nisimura 
    770  1.24  nisimura 		nsr = dme_read(sc, DM9000_NSR);
    771  1.24  nisimura 		if (nsr & DM9000_NSR_TX1END) {
    772  1.24  nisimura 			tsr = dme_read(sc, DM9000_TSR1);
    773  1.24  nisimura 			TX_DPRINTF(("dme_intr: Sent using channel 0\n"));
    774  1.24  nisimura 		} else if (nsr & DM9000_NSR_TX2END) {
    775  1.24  nisimura 			tsr = dme_read(sc, DM9000_TSR2);
    776  1.24  nisimura 			TX_DPRINTF(("dme_intr: Sent using channel 1\n"));
    777  1.24  nisimura 		}
    778   1.4  nisimura 
    779  1.24  nisimura 		if (tsr == 0x0) {
    780  1.24  nisimura 			/* Frame successfully sent */
    781  1.24  nisimura 			if_statinc(ifp, if_opackets);
    782  1.24  nisimura 		} else {
    783  1.24  nisimura 			if_statinc(ifp, if_oerrors);
    784  1.24  nisimura 		}
    785   1.4  nisimura 
    786  1.24  nisimura 		/* If we have nothing ready to transmit, prepare something */
    787  1.24  nisimura 		if (!sc->txready)
    788  1.24  nisimura 			dme_prepare(ifp);
    789   1.4  nisimura 
    790  1.24  nisimura 		if (sc->txready)
    791  1.24  nisimura 			dme_transmit(ifp);
    792   1.1     ahoka 
    793  1.24  nisimura 		/* Prepare the next frame */
    794  1.24  nisimura 		dme_prepare(ifp);
    795   1.1     ahoka 
    796  1.24  nisimura 		if_schedule_deferred_start(ifp);
    797  1.24  nisimura 	}
    798   1.1     ahoka 
    799  1.24  nisimura 	/* Enable interrupts again */
    800   1.1     ahoka 	dme_write(sc, DM9000_IMR,
    801   1.1     ahoka 	    DM9000_IMR_PAR | DM9000_IMR_PRM | DM9000_IMR_PTM);
    802   1.1     ahoka 
    803  1.24  nisimura 	DPRINTF(("dme_intr: End\n"));
    804  1.24  nisimura 
    805  1.24  nisimura 	return (isr != 0);
    806  1.24  nisimura }
    807   1.4  nisimura 
    808  1.24  nisimura static int
    809  1.24  nisimura dme_ioctl(struct ifnet *ifp, u_long cmd, void *data)
    810  1.24  nisimura {
    811  1.24  nisimura 	struct dme_softc *sc = ifp->if_softc;
    812  1.24  nisimura 	struct ifreq *ifr = (struct ifreq *)data;
    813  1.24  nisimura 	struct ifmedia *ifm = &sc->sc_mii.mii_media;
    814  1.24  nisimura 	int s, error;
    815   1.1     ahoka 
    816  1.24  nisimura 	s = splnet();
    817  1.24  nisimura 	switch (cmd) {
    818  1.24  nisimura 	case SIOCSIFMEDIA:
    819  1.24  nisimura 		/* Flow control requires full-duplex mode. */
    820  1.24  nisimura 		if (IFM_SUBTYPE(ifr->ifr_media) == IFM_AUTO ||
    821  1.24  nisimura 		    (ifr->ifr_media & IFM_FDX) == 0)
    822  1.24  nisimura 			ifr->ifr_media &= ~IFM_ETH_FMASK;
    823  1.24  nisimura 		if (IFM_SUBTYPE(ifr->ifr_media) != IFM_AUTO) {
    824  1.24  nisimura 			if ((ifr->ifr_media & IFM_ETH_FMASK) == IFM_FLOW) {
    825  1.24  nisimura 				ifr->ifr_media |=
    826  1.24  nisimura 					IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE;
    827  1.24  nisimura 			}
    828  1.24  nisimura 		}
    829  1.24  nisimura 		error = ifmedia_ioctl(ifp, ifr, ifm, cmd);
    830  1.24  nisimura 		break;
    831  1.24  nisimura 	default:
    832  1.24  nisimura 		if ((error = ether_ioctl(ifp, cmd, data)) != ENETRESET)
    833  1.24  nisimura 			break;
    834  1.24  nisimura 		error = 0;
    835  1.24  nisimura 		if (cmd == SIOCSIFCAP)
    836  1.24  nisimura 			error = (*ifp->if_init)(ifp);
    837  1.24  nisimura 		else if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI)
    838  1.24  nisimura 			;
    839  1.24  nisimura 		else if (ifp->if_flags && IFF_RUNNING) {
    840  1.24  nisimura 			/* Address list has changed, reconfigure filter */
    841  1.24  nisimura 			dme_set_rcvfilt(sc);
    842  1.24  nisimura 		}
    843  1.24  nisimura 		break;
    844  1.24  nisimura 	}
    845  1.24  nisimura 	splx(s);
    846  1.24  nisimura 	return error;
    847   1.4  nisimura }
    848   1.4  nisimura 
    849  1.24  nisimura static struct mbuf *
    850  1.24  nisimura dme_alloc_receive_buffer(struct ifnet *ifp, unsigned int frame_length)
    851   1.4  nisimura {
    852  1.24  nisimura 	struct dme_softc *sc = ifp->if_softc;
    853  1.24  nisimura 	struct mbuf *m;
    854  1.24  nisimura 	int pad, quantum;
    855  1.23  nisimura 
    856  1.24  nisimura 	quantum = sc->sc_data_width;
    857  1.24  nisimura 	MGETHDR(m, M_DONTWAIT, MT_DATA);
    858  1.24  nisimura 	if (m == NULL)
    859  1.24  nisimura 		return NULL;
    860   1.4  nisimura 
    861  1.24  nisimura 	m_set_rcvif(m, ifp);
    862  1.24  nisimura 	/* Ensure that we always allocate an even number of
    863  1.24  nisimura 	 * bytes in order to avoid writing beyond the buffer
    864  1.24  nisimura 	 */
    865  1.24  nisimura 	m->m_pkthdr.len = frame_length + (frame_length % quantum);
    866  1.24  nisimura 	pad = ALIGN(sizeof(struct ether_header)) -
    867  1.24  nisimura 		sizeof(struct ether_header);
    868  1.24  nisimura 	/* All our frames have the CRC attached */
    869  1.24  nisimura 	m->m_flags |= M_HASFCS;
    870  1.24  nisimura 	if (m->m_pkthdr.len + pad > MHLEN) {
    871  1.24  nisimura 		MCLGET(m, M_DONTWAIT);
    872  1.24  nisimura 		if ((m->m_flags & M_EXT) == 0) {
    873  1.24  nisimura 			m_freem(m);
    874  1.24  nisimura 			return NULL;
    875   1.4  nisimura 		}
    876   1.4  nisimura 	}
    877  1.24  nisimura 
    878  1.24  nisimura 	m->m_data += pad;
    879  1.24  nisimura 	m->m_len = frame_length + (frame_length % quantum);
    880  1.24  nisimura 
    881  1.24  nisimura 	return m;
    882   1.4  nisimura }
    883   1.4  nisimura 
    884  1.24  nisimura static int
    885  1.24  nisimura pkt_write_2(struct dme_softc *sc, struct mbuf *bufChain)
    886   1.4  nisimura {
    887   1.4  nisimura 	int left_over_count = 0; /* Number of bytes from previous mbuf, which
    888   1.4  nisimura 				    need to be written with the next.*/
    889   1.4  nisimura 	uint16_t left_over_buf = 0;
    890   1.4  nisimura 	int length = 0;
    891   1.4  nisimura 	struct mbuf *buf;
    892   1.4  nisimura 	uint8_t *write_ptr;
    893   1.4  nisimura 
    894   1.4  nisimura 	/* We expect that the DM9000 has been setup to accept writes before
    895   1.4  nisimura 	   this function is called. */
    896   1.4  nisimura 
    897   1.4  nisimura 	for (buf = bufChain; buf != NULL; buf = buf->m_next) {
    898   1.4  nisimura 		int to_write = buf->m_len;
    899   1.4  nisimura 
    900   1.4  nisimura 		length += to_write;
    901   1.4  nisimura 
    902   1.4  nisimura 		write_ptr = buf->m_data;
    903   1.4  nisimura 		while (to_write > 0 ||
    904  1.17   msaitoh 		    (buf->m_next == NULL && left_over_count > 0)) {
    905   1.4  nisimura 			if (left_over_count > 0) {
    906   1.4  nisimura 				uint8_t b = 0;
    907  1.24  nisimura 				DPRINTF(("pkt_write_16: "
    908   1.4  nisimura 					 "Writing left over byte\n"));
    909   1.4  nisimura 
    910   1.4  nisimura 				if (to_write > 0) {
    911   1.4  nisimura 					b = *write_ptr;
    912   1.4  nisimura 					to_write--;
    913   1.4  nisimura 					write_ptr++;
    914   1.4  nisimura 
    915   1.4  nisimura 					DPRINTF(("Took single byte\n"));
    916   1.4  nisimura 				} else {
    917   1.4  nisimura 					DPRINTF(("Leftover in last run\n"));
    918   1.4  nisimura 					length++;
    919   1.4  nisimura 				}
    920   1.4  nisimura 
    921   1.4  nisimura 				/* Does shift direction depend on endianess? */
    922   1.4  nisimura 				left_over_buf = left_over_buf | (b << 8);
    923   1.4  nisimura 
    924   1.4  nisimura 				bus_space_write_2(sc->sc_iot, sc->sc_ioh,
    925   1.4  nisimura 						  sc->dme_data, left_over_buf);
    926   1.4  nisimura 				TX_DATA_DPRINTF(("%02X ", left_over_buf));
    927   1.4  nisimura 				left_over_count = 0;
    928   1.4  nisimura 			} else if ((long)write_ptr % 2 != 0) {
    929   1.4  nisimura 				/* Misaligned data */
    930  1.24  nisimura 				DPRINTF(("pkt_write_16: "
    931   1.4  nisimura 					 "Detected misaligned data\n"));
    932   1.4  nisimura 				left_over_buf = *write_ptr;
    933   1.4  nisimura 				left_over_count = 1;
    934   1.4  nisimura 				write_ptr++;
    935   1.4  nisimura 				to_write--;
    936   1.4  nisimura 			} else {
    937   1.4  nisimura 				int i;
    938   1.7  macallan 				uint16_t *dptr = (uint16_t *)write_ptr;
    939   1.4  nisimura 
    940   1.4  nisimura 				/* A block of aligned data. */
    941  1.17   msaitoh 				for (i = 0; i < to_write / 2; i++) {
    942   1.4  nisimura 					/* buf will be half-word aligned
    943   1.4  nisimura 					 * all the time
    944   1.4  nisimura 					 */
    945   1.4  nisimura 					bus_space_write_2(sc->sc_iot,
    946   1.7  macallan 					    sc->sc_ioh, sc->dme_data, *dptr);
    947   1.4  nisimura 					TX_DATA_DPRINTF(("%02X %02X ",
    948   1.7  macallan 					    *dptr & 0xFF, (*dptr >> 8) & 0xFF));
    949   1.4  nisimura 					dptr++;
    950   1.4  nisimura 				}
    951   1.4  nisimura 
    952   1.7  macallan 				write_ptr += i * 2;
    953   1.4  nisimura 				if (to_write % 2 != 0) {
    954  1.24  nisimura 					DPRINTF(("pkt_write_16: "
    955   1.4  nisimura 						 "to_write %% 2: %d\n",
    956   1.4  nisimura 						 to_write % 2));
    957   1.4  nisimura 					left_over_count = 1;
    958   1.4  nisimura 					/* XXX: Does this depend on
    959   1.4  nisimura 					 * the endianess?
    960   1.4  nisimura 					 */
    961   1.4  nisimura 					left_over_buf = *write_ptr;
    962   1.4  nisimura 
    963   1.4  nisimura 					write_ptr++;
    964   1.4  nisimura 					to_write--;
    965  1.24  nisimura 					DPRINTF(("pkt_write_16: "
    966   1.4  nisimura 						 "to_write (after): %d\n",
    967   1.4  nisimura 						 to_write));
    968  1.24  nisimura 					DPRINTF(("pkt_write_16: i * 2: %d\n",
    969   1.4  nisimura 						 i*2));
    970   1.4  nisimura 				}
    971   1.7  macallan 				to_write -= i * 2;
    972   1.4  nisimura 			}
    973  1.18   msaitoh 		} /* while (...) */
    974  1.18   msaitoh 	} /* for (...) */
    975   1.4  nisimura 
    976   1.4  nisimura 	return length;
    977   1.4  nisimura }
    978   1.4  nisimura 
    979  1.24  nisimura static int
    980  1.24  nisimura pkt_read_2(struct dme_softc *sc, struct mbuf **outBuf)
    981   1.4  nisimura {
    982  1.24  nisimura 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
    983   1.4  nisimura 	uint8_t rx_status;
    984   1.4  nisimura 	struct mbuf *m;
    985   1.4  nisimura 	uint16_t data;
    986   1.4  nisimura 	uint16_t frame_length;
    987   1.4  nisimura 	uint16_t i;
    988   1.4  nisimura 	uint16_t *buf;
    989   1.4  nisimura 
    990   1.7  macallan 	data = bus_space_read_2(sc->sc_iot, sc->sc_ioh, sc->dme_data);
    991  1.24  nisimura 	rx_status = data & 0xFF;
    992   1.4  nisimura 
    993   1.4  nisimura 	frame_length = bus_space_read_2(sc->sc_iot,
    994   1.4  nisimura 					sc->sc_ioh, sc->dme_data);
    995   1.4  nisimura 	if (frame_length > ETHER_MAX_LEN) {
    996   1.4  nisimura 		printf("Got frame of length: %d\n", frame_length);
    997   1.4  nisimura 		printf("ETHER_MAX_LEN is: %d\n", ETHER_MAX_LEN);
    998   1.4  nisimura 		panic("Something is rotten");
    999   1.4  nisimura 	}
   1000  1.17   msaitoh 	RX_DPRINTF(("dme_receive: rx_statux: 0x%x, frame_length: %d\n",
   1001  1.17   msaitoh 		rx_status, frame_length));
   1002   1.4  nisimura 
   1003   1.4  nisimura 	m = dme_alloc_receive_buffer(ifp, frame_length);
   1004   1.8  macallan 	if (m == NULL) {
   1005   1.8  macallan 		/*
   1006   1.8  macallan 		 * didn't get a receive buffer, so we read the rest of the
   1007  1.24  nisimura 		 * frame, throw it away and return an error
   1008   1.8  macallan 		 */
   1009  1.24  nisimura 		for (i = 0; i < frame_length; i += 2) {
   1010   1.8  macallan 			data = bus_space_read_2(sc->sc_iot,
   1011   1.8  macallan 					sc->sc_ioh, sc->dme_data);
   1012   1.8  macallan 		}
   1013   1.8  macallan 		*outBuf = NULL;
   1014   1.8  macallan 		return 0;
   1015   1.8  macallan 	}
   1016   1.4  nisimura 
   1017   1.4  nisimura 	buf = mtod(m, uint16_t*);
   1018   1.4  nisimura 
   1019   1.4  nisimura 	RX_DPRINTF(("dme_receive: "));
   1020   1.4  nisimura 
   1021  1.24  nisimura 	for (i = 0; i < frame_length; i += 2) {
   1022   1.4  nisimura 		data = bus_space_read_2(sc->sc_iot,
   1023   1.4  nisimura 					sc->sc_ioh, sc->dme_data);
   1024   1.4  nisimura 		if ( (frame_length % 2 != 0) &&
   1025   1.7  macallan 		     (i == frame_length - 1) ) {
   1026   1.4  nisimura 			data = data & 0xff;
   1027   1.4  nisimura 			RX_DPRINTF((" L "));
   1028   1.4  nisimura 		}
   1029   1.4  nisimura 		*buf = data;
   1030   1.4  nisimura 		buf++;
   1031   1.4  nisimura 		RX_DATA_DPRINTF(("%02X %02X ", data & 0xff,
   1032   1.7  macallan 				 (data >> 8) & 0xff));
   1033   1.4  nisimura 	}
   1034   1.4  nisimura 
   1035   1.4  nisimura 	RX_DATA_DPRINTF(("\n"));
   1036   1.4  nisimura 	RX_DPRINTF(("Read %d bytes\n", i));
   1037   1.4  nisimura 
   1038   1.4  nisimura 	*outBuf = m;
   1039   1.4  nisimura 	return rx_status;
   1040   1.4  nisimura }
   1041   1.4  nisimura 
   1042  1.24  nisimura static int
   1043  1.24  nisimura pkt_write_1(struct dme_softc *sc, struct mbuf *bufChain)
   1044   1.6  macallan {
   1045   1.6  macallan 	int length = 0, i;
   1046   1.6  macallan 	struct mbuf *buf;
   1047   1.6  macallan 	uint8_t *write_ptr;
   1048   1.6  macallan 
   1049  1.17   msaitoh 	/*
   1050  1.17   msaitoh 	 * We expect that the DM9000 has been setup to accept writes before
   1051  1.17   msaitoh 	 * this function is called.
   1052  1.17   msaitoh 	 */
   1053   1.6  macallan 
   1054   1.6  macallan 	for (buf = bufChain; buf != NULL; buf = buf->m_next) {
   1055   1.6  macallan 		int to_write = buf->m_len;
   1056   1.6  macallan 
   1057   1.6  macallan 		length += to_write;
   1058   1.6  macallan 
   1059   1.6  macallan 		write_ptr = buf->m_data;
   1060   1.7  macallan 		for (i = 0; i < to_write; i++) {
   1061   1.6  macallan 			bus_space_write_1(sc->sc_iot, sc->sc_ioh,
   1062   1.6  macallan 			    sc->dme_data, *write_ptr);
   1063   1.6  macallan 			write_ptr++;
   1064   1.6  macallan 		}
   1065  1.18   msaitoh 	} /* for (...) */
   1066   1.6  macallan 
   1067   1.6  macallan 	return length;
   1068   1.6  macallan }
   1069   1.6  macallan 
   1070  1.24  nisimura static int
   1071  1.24  nisimura pkt_read_1(struct dme_softc *sc, struct mbuf **outBuf)
   1072   1.6  macallan {
   1073  1.24  nisimura 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
   1074   1.6  macallan 	uint8_t rx_status;
   1075   1.6  macallan 	struct mbuf *m;
   1076   1.6  macallan 	uint8_t *buf;
   1077   1.6  macallan 	uint16_t frame_length;
   1078   1.6  macallan 	uint16_t i, reg;
   1079   1.6  macallan 	uint8_t data;
   1080   1.6  macallan 
   1081   1.6  macallan 	reg = bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->dme_data);
   1082   1.6  macallan 	reg |= bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->dme_data) << 8;
   1083   1.6  macallan 	rx_status = reg & 0xFF;
   1084   1.6  macallan 
   1085   1.6  macallan 	reg = bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->dme_data);
   1086   1.6  macallan 	reg |= bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->dme_data) << 8;
   1087   1.6  macallan 	frame_length = reg;
   1088   1.7  macallan 
   1089   1.6  macallan 	if (frame_length > ETHER_MAX_LEN) {
   1090   1.6  macallan 		printf("Got frame of length: %d\n", frame_length);
   1091   1.6  macallan 		printf("ETHER_MAX_LEN is: %d\n", ETHER_MAX_LEN);
   1092   1.6  macallan 		panic("Something is rotten");
   1093   1.6  macallan 	}
   1094   1.6  macallan 	RX_DPRINTF(("dme_receive: "
   1095   1.6  macallan 		    "rx_statux: 0x%x, frame_length: %d\n",
   1096   1.6  macallan 		    rx_status, frame_length));
   1097   1.6  macallan 
   1098   1.6  macallan 	m = dme_alloc_receive_buffer(ifp, frame_length);
   1099   1.8  macallan 	if (m == NULL) {
   1100   1.8  macallan 		/*
   1101   1.8  macallan 		 * didn't get a receive buffer, so we read the rest of the
   1102  1.24  nisimura 		 * frame, throw it away and return an error
   1103   1.8  macallan 		 */
   1104   1.8  macallan 		for (i = 0; i < frame_length; i++ ) {
   1105   1.8  macallan 			data = bus_space_read_2(sc->sc_iot,
   1106   1.8  macallan 					sc->sc_ioh, sc->dme_data);
   1107   1.8  macallan 		}
   1108   1.8  macallan 		*outBuf = NULL;
   1109   1.8  macallan 		return 0;
   1110   1.8  macallan 	}
   1111   1.6  macallan 
   1112   1.7  macallan 	buf = mtod(m, uint8_t *);
   1113   1.6  macallan 
   1114   1.6  macallan 	RX_DPRINTF(("dme_receive: "));
   1115  1.24  nisimura 	for (i = 0; i< frame_length; i += 1) {
   1116   1.7  macallan 		data = bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->dme_data);
   1117   1.6  macallan 		*buf = data;
   1118   1.6  macallan 		buf++;
   1119   1.6  macallan 		RX_DATA_DPRINTF(("%02X ", data));
   1120   1.6  macallan 	}
   1121   1.6  macallan 
   1122   1.6  macallan 	RX_DATA_DPRINTF(("\n"));
   1123   1.6  macallan 	RX_DPRINTF(("Read %d bytes\n", i));
   1124   1.6  macallan 
   1125   1.6  macallan 	*outBuf = m;
   1126   1.6  macallan 	return rx_status;
   1127   1.6  macallan }
   1128