Ejemplo n.º 1
0
int
atachkpwr(struct dkdev_ata *l, int n)
{
    struct dvata_chan *chan = &l->chan[n];

    CSR_WRITE_1(chan->cmd + _CMD, ATA_CMD_CHKPWR);
    (void)CSR_READ_1(chan->alt);
    delay(10 * 1000);
    return CSR_READ_1(chan->cmd + _NSECT);
}
Ejemplo n.º 2
0
static void
dump_regs(Environ *e, Self *s)
{
	dprintf("\n");
	dprintf("ethxpro: scb_rus/scb_cus: %#x\n", CSR_READ_1(s, CSR_SCB_RUSCUS));
	dprintf("ethxpro: scb_statack: %#x\n", CSR_READ_1(s, CSR_SCB_STATACK));
	dprintf("ethxpro: scb_command: %#x\n", CSR_READ_1(s, CSR_SCB_COMMAND));
	dprintf("ethxpro: scb_intrcntl: %#x\n", CSR_READ_1(s, CSR_SCB_INTRCNTL));
	dprintf("ethxpro: scb_general: %#x\n", CSR_READ_4(s, CSR_SCB_GENERAL));
	dprintf("ethxpro: port: %#x\n", CSR_READ_4(s, CSR_PORT));
	dprintf("ethxpro: flash control: %#x\n", CSR_READ_2(s, CSR_FLASHCONTROL));
	dprintf("ethxpro: eeprom ctrl: %#x\n", CSR_READ_2(s, CSR_EEPROMCONTROL));
	dprintf("ethxpro: mdi control: %#x\n", CSR_READ_4(s, CSR_MDICONTROL));
}
Ejemplo n.º 3
0
/* clear idle and standby timers to spin up the drive */
void
wakeup_drive(struct dkdev_ata *l, int n)
{
    struct dvata_chan *chan = &l->chan[n];

    CSR_WRITE_1(chan->cmd + _NSECT, 0);
    CSR_WRITE_1(chan->cmd + _CMD, ATA_CMD_IDLE);
    (void)CSR_READ_1(chan->alt);
    delay(10 * 1000);
    CSR_WRITE_1(chan->cmd + _NSECT, 0);
    CSR_WRITE_1(chan->cmd + _CMD, ATA_CMD_STANDBY);
    (void)CSR_READ_1(chan->alt);
    delay(10 * 1000);
}
Ejemplo n.º 4
0
void
ste_txeoc(struct ste_softc *sc)
{
	u_int8_t		txstat;
	struct ifnet		*ifp;

	ifp = &sc->arpcom.ac_if;

	while ((txstat = CSR_READ_1(sc, STE_TX_STATUS)) &
	    STE_TXSTATUS_TXDONE) {
		if (txstat & STE_TXSTATUS_UNDERRUN ||
		    txstat & STE_TXSTATUS_EXCESSCOLLS ||
		    txstat & STE_TXSTATUS_RECLAIMERR) {
			ifp->if_oerrors++;
			printf("%s: transmission error: %x\n",
			    sc->sc_dev.dv_xname, txstat);

			ste_reset(sc);
			ste_init(sc);

			if (txstat & STE_TXSTATUS_UNDERRUN &&
			    sc->ste_tx_thresh < ETHER_MAX_DIX_LEN) {
				sc->ste_tx_thresh += STE_MIN_FRAMELEN;
				printf("%s: tx underrun, increasing tx"
				    " start threshold to %d bytes\n",
				    sc->sc_dev.dv_xname, sc->ste_tx_thresh);
			}
			CSR_WRITE_2(sc, STE_TX_STARTTHRESH, sc->ste_tx_thresh);
			CSR_WRITE_2(sc, STE_TX_RECLAIM_THRESH,
			    (ETHER_MAX_DIX_LEN >> 4));
		}
		ste_init(sc);
		CSR_WRITE_2(sc, STE_TX_STATUS, txstat);
	}
Ejemplo n.º 5
0
static uint32_t
vr_mii_bitbang_read(device_t self)
{
	struct vr_softc *sc = device_private(self);

	return (CSR_READ_1(sc, VR_MIICMD));
}
Ejemplo n.º 6
0
static void
ex_probemedia(void)
{
	int i, j;
	struct mtabentry *m;

	/* test for presence of connectors */
	GO_WINDOW(3);
	i = CSR_READ_1(ELINK_W3_RESET_OPTIONS);
	j = (CSR_READ_2(ELINK_W3_INTERNAL_CONFIG + 2) & CONFIG_MEDIAMASK)
		>> CONFIG_MEDIAMASK_SHIFT;
	GO_WINDOW(0);

	for (ether_medium = 0, m = mediatab;
	     ether_medium < sizeof(mediatab) / sizeof(mediatab[0]);
	     ether_medium++, m++) {
		if (j == m->address_cfg) {
			if (!(i & m->config_bit)) {
				printf("%s not present\n", m->name);
				goto bad;
			}
			printf("using %s\n", m->name);
			return;
		}
	}
	printf("unknown connector\n");
bad:
	ether_medium = -1;
}
Ejemplo n.º 7
0
/*
 * Read a word of data stored in the EEPROM at address 'addr.'
 */
uint16_t
rtk_read_eeprom(struct rtk_softc *sc, int addr, int addr_len)
{
	uint16_t word;
	int i;

	/* Enter EEPROM access mode. */
	CSR_WRITE_1(sc, RTK_EECMD, RTK_EEMODE_PROGRAM);
	EE_DELAY();
	EE_SET(RTK_EE_SEL);

	/*
	 * Send address of word we want to read.
	 */
	rtk_eeprom_putbyte(sc, addr, addr_len);

	/*
	 * Start reading bits from EEPROM.
	 */
	word = 0;
	for (i = 16; i > 0; i--) {
		EE_SET(RTK_EE_CLK);
		EE_DELAY();
		if (CSR_READ_1(sc, RTK_EECMD) & RTK_EE_DATAOUT)
			word |= 1 << (i - 1);
		EE_CLR(RTK_EE_CLK);
		EE_DELAY();
	}

	/* Turn off EEPROM access mode. */
	CSR_WRITE_1(sc, RTK_EECMD, RTK_EEMODE_OFF);

	return word;
}
Ejemplo n.º 8
0
/* wait for the command to be accepted but not necessarily completed
 */
static void
scb_wait(Self *s)
{
	int i = 10000;

	while (CSR_READ_1(s, CSR_SCB_COMMAND) && --i)
		DELAY(1);
}
Ejemplo n.º 9
0
static int
ex_look_for_card(struct ex_softc *sc)
{
	int count1, count2;

	/*
	 * Check for the i82595 signature, and check that the round robin
	 * counter actually advances.
	 */
	if (((count1 = CSR_READ_1(sc, ID_REG)) & Id_Mask) != Id_Sig)
		return(0);
	count2 = CSR_READ_1(sc, ID_REG);
	count2 = CSR_READ_1(sc, ID_REG);
	count2 = CSR_READ_1(sc, ID_REG);

	return((count2 & Counter_bits) == ((count1 + 0xc0) & Counter_bits));
}
Ejemplo n.º 10
0
/*
 * Program the 64-bit multicast hash filter.
 */
static void
vr_setmulti(struct vr_softc *sc)
{
	struct ifnet *ifp;
	int h = 0;
	uint32_t hashes[2] = { 0, 0 };
	struct ether_multistep step;
	struct ether_multi *enm;
	int mcnt = 0;
	uint8_t rxfilt;

	ifp = &sc->vr_ec.ec_if;

	rxfilt = CSR_READ_1(sc, VR_RXCFG);

	if (ifp->if_flags & IFF_PROMISC) {
allmulti:
		ifp->if_flags |= IFF_ALLMULTI;
		rxfilt |= VR_RXCFG_RX_MULTI;
		CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
		CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF);
		CSR_WRITE_4(sc, VR_MAR1, 0xFFFFFFFF);
		return;
	}

	/* first, zot all the existing hash bits */
	CSR_WRITE_4(sc, VR_MAR0, 0);
	CSR_WRITE_4(sc, VR_MAR1, 0);

	/* now program new ones */
	ETHER_FIRST_MULTI(step, &sc->vr_ec, enm);
	while (enm != NULL) {
		if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
		    ETHER_ADDR_LEN) != 0)
			goto allmulti;

		h = vr_calchash(enm->enm_addrlo);

		if (h < 32)
			hashes[0] |= (1 << h);
		else
			hashes[1] |= (1 << (h - 32));
		ETHER_NEXT_MULTI(step, enm);
		mcnt++;
	}

	ifp->if_flags &= ~IFF_ALLMULTI;

	if (mcnt)
		rxfilt |= VR_RXCFG_RX_MULTI;
	else
		rxfilt &= ~VR_RXCFG_RX_MULTI;

	CSR_WRITE_4(sc, VR_MAR0, hashes[0]);
	CSR_WRITE_4(sc, VR_MAR1, hashes[1]);
	CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
}
Ejemplo n.º 11
0
/*
 * Wait for the previous command to be accepted (but not necessarily
 * completed).
 */
static inline void
fxp_scb_wait()
{
    int i = 10000;

    while (CSR_READ_1(FXP_CSR_SCB_COMMAND) && --i)
        DELAY(1);
    if (i == 0)
        printf("fxp: WARNING: SCB timed out!\n");
}
Ejemplo n.º 12
0
static int
probe_drive(struct dkdev_ata *l, int n)
{
    struct dvata_chan *chan = &l->chan[n];
    uint16_t *p;
    int i;

    CSR_WRITE_1(chan->cmd + _CMD, ATA_CMD_IDENT);
    (void)CSR_READ_1(chan->alt);
    delay(10 * 1000);
    if (spinwait_unbusy(l, n, 1000, NULL) == 0)
        return 0;

    p = (uint16_t *)l->iobuf;
    for (i = 0; i < 512; i += 2) {
        /* need to have bswap16 */
        *p++ = iole16toh(chan->cmd + _DAT);
    }
    (void)CSR_READ_1(chan->cmd + _STS);
    return 1;
}
Ejemplo n.º 13
0
void
ste_iff(struct ste_softc *sc)
{
	struct ifnet		*ifp = &sc->arpcom.ac_if;
	struct arpcom		*ac = &sc->arpcom;
	struct ether_multi	*enm;
	struct ether_multistep	step;
	u_int32_t		rxmode, hashes[2];
	int			h = 0;

	rxmode = CSR_READ_1(sc, STE_RX_MODE);
	rxmode &= ~(STE_RXMODE_ALLMULTI | STE_RXMODE_BROADCAST |
	    STE_RXMODE_MULTIHASH | STE_RXMODE_PROMISC |
	    STE_RXMODE_UNICAST);
	bzero(hashes, sizeof(hashes));
	ifp->if_flags &= ~IFF_ALLMULTI;

	/*
	 * Always accept broadcast frames.
	 * Always accept frames destined to our station address.
	 */
	rxmode |= STE_RXMODE_BROADCAST | STE_RXMODE_UNICAST;

	if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) {
		ifp->if_flags |= IFF_ALLMULTI;
		rxmode |= STE_RXMODE_ALLMULTI;
		if (ifp->if_flags & IFF_PROMISC)
			rxmode |= STE_RXMODE_PROMISC;
	} else {
		rxmode |= STE_RXMODE_MULTIHASH;

		/* now program new ones */
		ETHER_FIRST_MULTI(step, ac, enm);
		while (enm != NULL) {
			h = ether_crc32_be(enm->enm_addrlo,
			    ETHER_ADDR_LEN) & 0x3F;

			if (h < 32)
				hashes[0] |= (1 << h);
			else
				hashes[1] |= (1 << (h - 32));

			ETHER_NEXT_MULTI(step, enm);
		}
	}

	CSR_WRITE_2(sc, STE_MAR0, hashes[0] & 0xFFFF);
	CSR_WRITE_2(sc, STE_MAR1, (hashes[0] >> 16) & 0xFFFF);
	CSR_WRITE_2(sc, STE_MAR2, hashes[1] & 0xFFFF);
	CSR_WRITE_2(sc, STE_MAR3, (hashes[1] >> 16) & 0xFFFF);
	CSR_WRITE_1(sc, STE_RX_MODE, rxmode);
}
Ejemplo n.º 14
0
void
rtk_reset(struct rtk_softc *sc)
{
	int i;

	CSR_WRITE_1(sc, RTK_COMMAND, RTK_CMD_RESET);

	for (i = 0; i < RTK_TIMEOUT; i++) {
		DELAY(10);
		if ((CSR_READ_1(sc, RTK_COMMAND) & RTK_CMD_RESET) == 0)
			break;
	}
	if (i == RTK_TIMEOUT)
		printf("%s: reset never completed!\n",
		    device_xname(sc->sc_dev));
}
Ejemplo n.º 15
0
static int
lba_read(struct disk *d, int64_t bno, int bcnt, void *buf)
{
    struct dkdev_ata *l;
    struct dvata_chan *chan;
    void (*issue)(struct dvata_chan *, int64_t, int);
    int n, rdcnt, i, k;
    uint16_t *p;
    const char *err;
    int error;

    l = d->dvops;
    n = d->unittag;
    p = (uint16_t *)buf;
    chan = &l->chan[n];
    error = 0;
    for ( ; bcnt > 0; bno += rdcnt, bcnt -= rdcnt) {
        issue = (bno < (1ULL<<28)) ? issue28 : issue48;
        rdcnt = (bcnt > 255) ? 255 : bcnt;
        (*issue)(chan, bno, rdcnt);
        for (k = 0; k < rdcnt; k++) {
            if (spinwait_unbusy(l, n, 1000, &err) == 0) {
                printf("%s blk %lld %s\n", d->xname, bno, err);
                error = EIO;
                break;
            }
            for (i = 0; i < 512; i += 2) {
                /* arrives in native order */
                *p++ = *(uint16_t *)(chan->cmd + _DAT);
            }
            /* clear irq if any */
            (void)CSR_READ_1(chan->cmd + _STS);
        }
    }
    return error;
}
Ejemplo n.º 16
0
int
spinwait_unbusy(struct dkdev_ata *l, int n, int milli, const char **err)
{
    struct dvata_chan *chan = &l->chan[n];
    int sts;
    const char *msg;

    /*
     * For best compatibility it is recommended to wait 400ns and
     * read the alternate status byte four times before the status
     * is valid.
     */
    delay(1);
    (void)CSR_READ_1(chan->alt);
    (void)CSR_READ_1(chan->alt);
    (void)CSR_READ_1(chan->alt);
    (void)CSR_READ_1(chan->alt);

    sts = CSR_READ_1(chan->cmd + _STS);
    while (milli-- > 0
            && sts != 0xff
            && (sts & (ATA_STS_BUSY|ATA_STS_DRDY)) != ATA_STS_DRDY) {
        delay(1000);
        sts = CSR_READ_1(chan->cmd + _STS);
    }

    msg = NULL;
    if (sts == 0xff)
        msg = "returned 0xff";
    else if (sts & ATA_STS_ERR)
        msg = "returned ERR";
    else if (sts & ATA_STS_BUSY)
        msg = "remains BUSY";
    else if ((sts & ATA_STS_DRDY) == 0)
        msg = "no DRDY";

    if (err != NULL)
        *err = msg;
    return msg == NULL;
}
Ejemplo n.º 17
0
/*
 * A frame has been uploaded: pass the resulting mbuf chain up to
 * the higher level protocols.
 *
 * You know there's something wrong with a PCI bus-master chip design.
 *
 * The receive operation is badly documented in the datasheet, so I'll
 * attempt to document it here. The driver provides a buffer area and
 * places its base address in the RX buffer start address register.
 * The chip then begins copying frames into the RX buffer. Each frame
 * is preceded by a 32-bit RX status word which specifies the length
 * of the frame and certain other status bits. Each frame (starting with
 * the status word) is also 32-bit aligned. The frame length is in the
 * first 16 bits of the status word; the lower 15 bits correspond with
 * the 'rx status register' mentioned in the datasheet.
 *
 * Note: to make the Alpha happy, the frame payload needs to be aligned
 * on a 32-bit boundary. To achieve this, we copy the data to mbuf
 * shifted forward 2 bytes.
 */
static void
rtk_rxeof(struct rtk_softc *sc)
{
	struct mbuf *m;
	struct ifnet *ifp;
	uint8_t *rxbufpos, *dst;
	u_int total_len, wrap;
	uint32_t rxstat;
	uint16_t cur_rx, new_rx;
	uint16_t limit;
	uint16_t rx_bytes, max_bytes;

	ifp = &sc->ethercom.ec_if;

	cur_rx = (CSR_READ_2(sc, RTK_CURRXADDR) + 16) % RTK_RXBUFLEN;

	/* Do not try to read past this point. */
	limit = CSR_READ_2(sc, RTK_CURRXBUF) % RTK_RXBUFLEN;

	if (limit < cur_rx)
		max_bytes = (RTK_RXBUFLEN - cur_rx) + limit;
	else
		max_bytes = limit - cur_rx;
	rx_bytes = 0;

	while ((CSR_READ_1(sc, RTK_COMMAND) & RTK_CMD_EMPTY_RXBUF) == 0) {
		rxbufpos = sc->rtk_rx_buf + cur_rx;
		bus_dmamap_sync(sc->sc_dmat, sc->recv_dmamap, cur_rx,
		    RTK_RXSTAT_LEN, BUS_DMASYNC_POSTREAD);
		rxstat = le32toh(*(uint32_t *)rxbufpos);
		bus_dmamap_sync(sc->sc_dmat, sc->recv_dmamap, cur_rx,
		    RTK_RXSTAT_LEN, BUS_DMASYNC_PREREAD);

		/*
		 * Here's a totally undocumented fact for you. When the
		 * RealTek chip is in the process of copying a packet into
		 * RAM for you, the length will be 0xfff0. If you spot a
		 * packet header with this value, you need to stop. The
		 * datasheet makes absolutely no mention of this and
		 * RealTek should be shot for this.
		 */
		total_len = rxstat >> 16;
		if (total_len == RTK_RXSTAT_UNFINISHED)
			break;

		if ((rxstat & RTK_RXSTAT_RXOK) == 0 ||
		    total_len < ETHER_MIN_LEN ||
		    total_len > (MCLBYTES - RTK_ETHER_ALIGN)) {
			ifp->if_ierrors++;

			/*
			 * submitted by:[netbsd-pcmcia:00484]
			 *	Takahiro Kambe <*****@*****.**>
			 * obtain from:
			 *     FreeBSD if_rl.c rev 1.24->1.25
			 *
			 */
#if 0
			if (rxstat & (RTK_RXSTAT_BADSYM|RTK_RXSTAT_RUNT|
			    RTK_RXSTAT_GIANT|RTK_RXSTAT_CRCERR|
			    RTK_RXSTAT_ALIGNERR)) {
				CSR_WRITE_2(sc, RTK_COMMAND, RTK_CMD_TX_ENB);
				CSR_WRITE_2(sc, RTK_COMMAND,
				    RTK_CMD_TX_ENB|RTK_CMD_RX_ENB);
				CSR_WRITE_4(sc, RTK_RXCFG, RTK_RXCFG_CONFIG);
				CSR_WRITE_4(sc, RTK_RXADDR,
				    sc->recv_dmamap->dm_segs[0].ds_addr);
				cur_rx = 0;
			}
			break;
#else
			rtk_init(ifp);
			return;
#endif
		}

		/* No errors; receive the packet. */
		rx_bytes += total_len + RTK_RXSTAT_LEN;

		/*
		 * Avoid trying to read more bytes than we know
		 * the chip has prepared for us.
		 */
		if (rx_bytes > max_bytes)
			break;

		/*
		 * Skip the status word, wrapping around to the beginning
		 * of the Rx area, if necessary.
		 */
		cur_rx = (cur_rx + RTK_RXSTAT_LEN) % RTK_RXBUFLEN;
		rxbufpos = sc->rtk_rx_buf + cur_rx;

		/*
		 * Compute the number of bytes at which the packet
		 * will wrap to the beginning of the ring buffer.
		 */
		wrap = RTK_RXBUFLEN - cur_rx;

		/*
		 * Compute where the next pending packet is.
		 */
		if (total_len > wrap)
			new_rx = total_len - wrap;
		else
			new_rx = cur_rx + total_len;
		/* Round up to 32-bit boundary. */
		new_rx = roundup2(new_rx, sizeof(uint32_t)) % RTK_RXBUFLEN;

		/*
		 * The RealTek chip includes the CRC with every
		 * incoming packet; trim it off here.
		 */
		total_len -= ETHER_CRC_LEN;

		/*
		 * Now allocate an mbuf (and possibly a cluster) to hold
		 * the packet. Note we offset the packet 2 bytes so that
		 * data after the Ethernet header will be 4-byte aligned.
		 */
		MGETHDR(m, M_DONTWAIT, MT_DATA);
		if (m == NULL) {
			printf("%s: unable to allocate Rx mbuf\n",
			    device_xname(sc->sc_dev));
			ifp->if_ierrors++;
			goto next_packet;
		}
		if (total_len > (MHLEN - RTK_ETHER_ALIGN)) {
			MCLGET(m, M_DONTWAIT);
			if ((m->m_flags & M_EXT) == 0) {
				printf("%s: unable to allocate Rx cluster\n",
				    device_xname(sc->sc_dev));
				ifp->if_ierrors++;
				m_freem(m);
				m = NULL;
				goto next_packet;
			}
		}
		m->m_data += RTK_ETHER_ALIGN;	/* for alignment */
		m->m_pkthdr.rcvif = ifp;
		m->m_pkthdr.len = m->m_len = total_len;
		dst = mtod(m, void *);

		/*
		 * If the packet wraps, copy up to the wrapping point.
		 */
		if (total_len > wrap) {
			bus_dmamap_sync(sc->sc_dmat, sc->recv_dmamap,
			    cur_rx, wrap, BUS_DMASYNC_POSTREAD);
			memcpy(dst, rxbufpos, wrap);
			bus_dmamap_sync(sc->sc_dmat, sc->recv_dmamap,
			    cur_rx, wrap, BUS_DMASYNC_PREREAD);
			cur_rx = 0;
			rxbufpos = sc->rtk_rx_buf;
			total_len -= wrap;
			dst += wrap;
		}

		/*
		 * ...and now the rest.
		 */
		bus_dmamap_sync(sc->sc_dmat, sc->recv_dmamap,
		    cur_rx, total_len, BUS_DMASYNC_POSTREAD);
		memcpy(dst, rxbufpos, total_len);
		bus_dmamap_sync(sc->sc_dmat, sc->recv_dmamap,
		    cur_rx, total_len, BUS_DMASYNC_PREREAD);

 next_packet:
		CSR_WRITE_2(sc, RTK_CURRXADDR, (new_rx - 16) % RTK_RXBUFLEN);
		cur_rx = new_rx;

		if (m == NULL)
			continue;

		ifp->if_ipackets++;

		bpf_mtap(ifp, m);
		/* pass it on. */
		(*ifp->if_input)(ifp, m);
	}
}
Ejemplo n.º 18
0
static void
ex_init_locked(struct ex_softc *sc)
{
	struct ifnet *		ifp = sc->ifp;
	int			i;
	unsigned short		temp_reg;

	DODEBUG(Start_End, printf("%s: ex_init: start\n", ifp->if_xname););

	sc->tx_timeout = 0;

	/*
	 * Load the ethernet address into the card.
	 */
	CSR_WRITE_1(sc, CMD_REG, Bank2_Sel);
	temp_reg = CSR_READ_1(sc, EEPROM_REG);
	if (temp_reg & Trnoff_Enable)
		CSR_WRITE_1(sc, EEPROM_REG, temp_reg & ~Trnoff_Enable);
	for (i = 0; i < ETHER_ADDR_LEN; i++)
		CSR_WRITE_1(sc, I_ADDR_REG0 + i, IF_LLADDR(sc->ifp)[i]);

	/*
	 * - Setup transmit chaining and discard bad received frames.
	 * - Match broadcast.
	 * - Clear test mode.
	 * - Set receiving mode.
	 */
	CSR_WRITE_1(sc, REG1, CSR_READ_1(sc, REG1) | Tx_Chn_Int_Md | Tx_Chn_ErStp | Disc_Bad_Fr);
	CSR_WRITE_1(sc, REG2, CSR_READ_1(sc, REG2) | No_SA_Ins | RX_CRC_InMem);
	CSR_WRITE_1(sc, REG3, CSR_READ_1(sc, REG3) & 0x3f /* XXX constants. */ );
	/*
Ejemplo n.º 19
0
Archivo: if_el.c Proyecto: MarginC/kame
/* Probe routine.  See if the card is there and at the right place. */
static int
el_probe(device_t dev)
{
	struct el_softc *sc;
	u_short base; /* Just for convenience */
	u_char station_addr[ETHER_ADDR_LEN];
	int i, rid;

	/* Grab some info for our structure */
	sc = device_get_softc(dev);

	if (isa_get_logicalid(dev))		/* skip PnP probes */
		return (ENXIO);

	if ((base = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0)
		return (ENXIO);

	/* First check the base */
	if((base < 0x280) || (base > 0x3f0)) {
		device_printf(dev,
		    "ioaddr must be between 0x280 and 0x3f0\n");
		return(ENXIO);
	}

	/* Temporarily map the resources. */
	rid = 0;
	sc->el_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
	    0, ~0, EL_IOSIZ, RF_ACTIVE);

	if (sc->el_res == NULL)
		return(ENXIO);

	sc->el_btag = rman_get_bustag(sc->el_res);
	sc->el_bhandle = rman_get_bushandle(sc->el_res);
	mtx_init(&sc->el_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
	    MTX_DEF | MTX_RECURSE);
	EL_LOCK(sc);

	/* Now attempt to grab the station address from the PROM
	 * and see if it contains the 3com vendor code.
	 */
	dprintf(("Probing 3c501 at 0x%x...\n",base));

	/* Reset the board */
	dprintf(("Resetting board...\n"));
	CSR_WRITE_1(sc,EL_AC,EL_AC_RESET);
	DELAY(5);
	CSR_WRITE_1(sc,EL_AC,0);
	dprintf(("Reading station address...\n"));
	/* Now read the address */
	for(i=0;i<ETHER_ADDR_LEN;i++) {
		CSR_WRITE_1(sc,EL_GPBL,i);
		station_addr[i] = CSR_READ_1(sc,EL_EAW);
	}

	/* Now release resources */
	bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->el_res);
	EL_UNLOCK(sc);
	mtx_destroy(&sc->el_mtx);

	dprintf(("Address is %6D\n",station_addr, ":"));

	/* If the vendor code is ok, return a 1.  We'll assume that
	 * whoever configured this system is right about the IRQ.
	 */
	if((station_addr[0] != 0x02) || (station_addr[1] != 0x60)
	   || (station_addr[2] != 0x8c)) {
		dprintf(("Bad vendor code.\n"));
		return(ENXIO);
	} else {
		dprintf(("Vendor code ok.\n"));
		/* Copy the station address into the arpcom structure */
		bcopy(station_addr,sc->arpcom.ac_enaddr,ETHER_ADDR_LEN);
	}

	device_set_desc(dev, "3Com 3c501 Ethernet");

	return(0);
}