diff options
Diffstat (limited to 'sys/i386/isa/if_rdp.c')
| -rw-r--r-- | sys/i386/isa/if_rdp.c | 1456 | 
1 files changed, 0 insertions, 1456 deletions
| diff --git a/sys/i386/isa/if_rdp.c b/sys/i386/isa/if_rdp.c deleted file mode 100644 index 0d29b0aba602a..0000000000000 --- a/sys/i386/isa/if_rdp.c +++ /dev/null @@ -1,1456 +0,0 @@ -/* - * Copyright 1998, Joerg Wunsch - * All rights reserved. - * - * 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 unmodified, 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 THE AUTHOR OR 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. - * - *	$Id: if_rdp.c,v 1.2 1998/12/21 18:11:10 joerg Exp $ - */ - -/* - * Device driver for RealTek RTL 8002 (`REDP') based pocket-ethernet - * adapters, hooked up to a printer port.  `rdp' is a shorthand for - * REDP since some tools like netstat work best if the interface name - * has no more than three letters. - * - * Driver configuration flags so far: - *   flags 0x1 -- assume 74S288 EEPROM (default 94C46) - *   flags 0x2 -- use `slow' mode (mode 3 of the packet driver, default 0) - * - * Maybe this driver will some day also work with the successor, RTL - * 8012 (`AREDP'), which is unfortunately not fully register- - * compatible with the 8002.  The 8012 offers support for faster - * transfer modi like bidirectional SPP and EPP, 64 K x 4 buffer - * memory as opposed to 16 K x 4 for the 8002, a multicast filter, and - * a builtin multiplexer that allows chaining a printer behind the - * ethernet adapter. - * - * About the only documentation i've been able to find about the RTL - * 8002 was the packet driver source code at ftp.realtek.com.tw, so - * this driver is somewhat based on the way the packet driver handles - * the chip.  The exact author of the packet driver is unknown, the - * only name that i could find in the source was someone called Chiu, - * supposedly an employee of RealTek.  So credits to them for that - * piece of code which has proven valuable to me. - * - * Later on, Leo kuo <leo@realtek.com.tw> has been very helpful to me - * by sending me a readable (PDF) file documenting the RTL 8012, which - * helped me to also understand the 8002, as well as by providing me - * with the source code of the 8012 packet driver that i haven't been - * able to find on the FTP site.  A big Thanks! goes here to RealTek - * for this kind of service. - */ - -#include "rdp.h" -#include "bpfilter.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/sockio.h> -#include <sys/malloc.h> -#include <sys/mbuf.h> -#include <sys/socket.h> -#include <sys/syslog.h> - -#include <net/ethernet.h> -#include <net/if.h> -#include <net/if_arp.h> -#include <net/if_dl.h> -#include <net/if_mib.h> - -#ifdef INET -#include <netinet/in.h> -#include <netinet/if_ether.h> -#endif - -#ifdef NS -#include <netns/ns.h> -#include <netns/ns_if.h> -#endif - -#if NBPFILTER > 0 -#include <net/bpf.h> -#endif - -#include <machine/clock.h> -#include <machine/md_var.h> - -#include <i386/isa/isa_device.h> -#include <i386/isa/icu.h> -#include <i386/isa/if_rdpreg.h> -#include <i386/isa/intr_machdep.h> - -#define IOCTL_CMD_T u_long - -/* - * Debug levels (ORed together): - *  != 0 - general (bad packets etc.) - *  2 - debug EEPROM IO - *  4 - debug interrupt status - */ -#undef DEBUG -#define DEBUG 0 - -/* - * rdp_softc: per interface info and status - */ -struct rdp_softc { -	struct arpcom arpcom;	/* -				 * Ethernet common, always goes first so -				 * a rdp_softc * can be cast into an -				 * arpcom * or into an ifnet *. -				 */ - -	/* -	 * local stuff, somewhat sorted by memory alignment class -	 */ -	u_short baseaddr;	/* IO port address */ -	u_short txsize;		/* tx size for next (buffered) packet, -				 * there's only one additional packet -				 * we can buffer, thus a single variable -				 * ought to be enough */ -	int txbusy;		/* tx is transmitting */ -	int txbuffered;		/* # of packets in tx buffer */ -	int slow;		/* use lpt_control to send data */ -	u_char irqenbit;	/* mirror of current Ctrl_IRQEN */ -	/* -	 * type of parameter EEPROM; device flags 0x1 selects 74S288 -	 */ -	enum { -		EEPROM_93C46, EEPROM_74S288 /* or 82S123 */ -	} eeprom; -}; - -static struct rdp_softc rdp_softc[NRDP]; - -/* - * Since there's no fixed location in the EEPROM about where to find - * the ethernet hardware address, we drop a table of valid OUIs here, - * and search through the EEPROM until we find a possible valid - * Ethernet address.  Only the first 16 bits of all possible OUIs are - * recorded in the table (as obtained from - * http://standards.ieee.org/regauth/oui/oui.txt). - */ - -static u_short allowed_ouis[] = { -	0x0000, 0x0001, 0x0002, 0x0004, 0x0005, 0x0006, 0x0007, -	0x0008, 0x0010, 0x001C, 0x0020, 0x0040, 0x0050, 0x0060, -	0x0070, 0x0080, 0x0090, 0x009D, 0x00A0, 0x00AA, 0x00BB, -	0x00C0, 0x00CF, 0x00DD, 0x00E0, 0x00E6, 0x0207, 0x021C, -	0x0260, 0x0270, 0x029D, 0x02AA, 0x02BB, 0x02C0, 0x02CF, -	0x02E6, 0x040A, 0x04E0, 0x0800, 0x08BB, 0x1000, 0x1100, -	0x8000, 0xAA00 -}; - -/* - * ISA bus support. - */ -static int rdp_probe		__P((struct isa_device *)); -static int rdp_attach		__P((struct isa_device *)); - -/* - * Required entry points. - */ -static void rdp_init(void *); -static int rdp_ioctl(struct ifnet *, IOCTL_CMD_T, caddr_t); -static void rdp_start(struct ifnet *); -static void rdp_reset(struct ifnet *); -static void rdp_watchdog(struct ifnet *); -static void rdpintr(int); - -/* - * REDP private functions. - */ - -static void rdp_stop(struct rdp_softc *); -static void rdp_rint(struct rdp_softc *); -static void rdp_get_packet(struct rdp_softc *, unsigned); -static u_short rdp_write_mbufs(struct rdp_softc *, struct mbuf *); -static int rdp_gethwaddr_93c46(struct rdp_softc *, u_char *); -static void rdp_gethwaddr_74s288(struct rdp_softc *, u_char *); -static void rdp_93c46_cmd(struct rdp_softc *, u_short, unsigned); -static u_short rdp_93c46_read(struct rdp_softc *); - -struct isa_driver rdpdriver = { -	rdp_probe, -	rdp_attach, -	"rdp", -	1			/* we wanna get a chance before lptN */ -}; - -/* - * REDP-specific functions. - * - * They are inlined, thus go first in this file.  Together with gcc's - * usual optimization, these functions probably come close to the - * packet driver's hand-optimized code. ;-) - * - * Comments are partially obtained from the packet driver as well. - * Some of the function names contain register names which don't make - * much sense for us, but i've kept them for easier reference in - * comparision to the packet driver. - * - * Some of the functions are currently not used by the driver; it's - * not quite clear whether we ever need them at all.  They are - * supposedly even slower than what is currently implemented as `slow' - * mode.  Right now, `fast' (default) mode is what the packet driver - * calls mode 0, slow mode is mode 3 (writing through lpt_control, - * reading twice). - * - * We should autoprobe the modi, as opposed to making them dependent - * on a kernel configuration flag. - */ - -/* - * read a nibble from rreg; end-of-data cmd is not issued; - * used for general register read. - * - * Unlike the packet driver's version, i'm shifting the result - * by 3 here (as opposed to within the caller's code) for clarity. - *  -- Joerg - */ -static __inline u_char -RdNib(struct rdp_softc *sc, u_char rreg) -{ - -	outb(sc->baseaddr + lpt_data, EOC + rreg); -	outb(sc->baseaddr + lpt_data, RdAddr + rreg); /* write addr */ -	(void)inb(sc->baseaddr + lpt_status); -	return (inb(sc->baseaddr + lpt_status) >> 3) & 0x0f; -} - -#if 0 -/* - * read a byte from MAR register through lpt_data; the low nibble is - * read prior to the high one; end-of-read command is not issued; used - * for remote DMA in mode 4 + 5 - */ -static __inline u_char -RdByte(struct rdp_softc *sc) -{ -	u_char hinib, lonib; - -	outb(sc->baseaddr + lpt_data, RdAddr + MAR); /* cmd for low nibble */ -	lonib = (inb(sc->baseaddr + lpt_status) >> 3) & 0x0f; -	outb(sc->baseaddr + lpt_data, RdAddr + MAR + HNib); -	hinib = (inb(sc->baseaddr + lpt_status) << 1) & 0xf0; -	return hinib + lonib; -} - - -/* - * read a byte from MAR register through lpt_data; the low nibble is - * read prior to the high one; end-of-read command is not issued; used - * for remote DMA in mode 6 + 7 - */ -static __inline u_char -RdByte1(struct rdp_softc *sc) -{ -	u_char hinib, lonib; - -	outb(sc->baseaddr + lpt_data, RdAddr + MAR); /* cmd for low nibble */ -	(void)inb(sc->baseaddr + lpt_status); -	lonib = (inb(sc->baseaddr + lpt_status) >> 3) & 0x0f; -	outb(sc->baseaddr + lpt_data, RdAddr + MAR + HNib); -	(void)inb(sc->baseaddr + lpt_status); -	hinib = (inb(sc->baseaddr + lpt_status) << 1) & 0xf0; -	return hinib + lonib; -} -#endif - - -/* - * read a byte from MAR register through lpt_control; the low nibble is - * read prior to the high one; end-of-read command is not issued; used - * for remote DMA in mode 0 + 1 - */ -static __inline u_char -RdByteA1(struct rdp_softc *sc) -{ -	u_char hinib, lonib; - -	outb(sc->baseaddr + lpt_control, Ctrl_LNibRead); -	lonib = (inb(sc->baseaddr + lpt_status) >> 3) & 0x0f; -	outb(sc->baseaddr + lpt_control, Ctrl_HNibRead); -	hinib = (inb(sc->baseaddr + lpt_status) << 1) & 0xf0; -	return hinib + lonib; -} - - -/* - * read a byte from MAR register through lpt_control; the low nibble is - * read prior to the high one; end-of-read command is not issued; used - * for remote DMA in mode 2 + 3 - */ -static __inline u_char -RdByteA2(struct rdp_softc *sc) -{ -	u_char hinib, lonib; - -	outb(sc->baseaddr + lpt_control, Ctrl_LNibRead); -	(void)inb(sc->baseaddr + lpt_status); -	lonib = (inb(sc->baseaddr + lpt_status) >> 3) & 0x0f; -	outb(sc->baseaddr + lpt_control, Ctrl_HNibRead); -	(void)inb(sc->baseaddr + lpt_status); -	hinib = (inb(sc->baseaddr + lpt_status) << 1) & 0xf0; -	return hinib + lonib; -} - -/* - * End-of-read cmd - */ -static __inline void -RdEnd(struct rdp_softc *sc, u_char rreg) -{ - -	outb(sc->baseaddr + lpt_data, EOC + rreg); -} - -/* - * Write a nibble to a register; end-of-write is issued. - * Used for general register write. - */ -static __inline void -WrNib(struct rdp_softc *sc, u_char wreg, u_char wdata) -{ - -	/* prepare and write address */ -	outb(sc->baseaddr + lpt_data, EOC + wreg); -	outb(sc->baseaddr + lpt_data, WrAddr + wreg); -	outb(sc->baseaddr + lpt_data, WrAddr + wreg); -	/* prepare and write data */ -	outb(sc->baseaddr + lpt_data, WrAddr + wdata); -	outb(sc->baseaddr + lpt_data, wdata); -	outb(sc->baseaddr + lpt_data, wdata); -	/* end-of-write */ -	outb(sc->baseaddr + lpt_data, EOC + wdata); -} - -/* - * Write a byte to a register; end-of-write is issued. - * Used for general register write. - */ -static __inline void -WrByte(struct rdp_softc *sc, u_char wreg, u_char wdata) -{ - -	/* prepare and write address */ -	outb(sc->baseaddr + lpt_data, EOC + wreg); -	outb(sc->baseaddr + lpt_data, WrAddr + wreg); -	outb(sc->baseaddr + lpt_data, WrAddr + wreg); -	/* prepare and write low nibble */ -	outb(sc->baseaddr + lpt_data, WrAddr + (wdata & 0x0F)); -	outb(sc->baseaddr + lpt_data, (wdata & 0x0F)); -	outb(sc->baseaddr + lpt_data, (wdata & 0x0F)); -	/* prepare and write high nibble */ -	wdata >>= 4; -	outb(sc->baseaddr + lpt_data, wdata); -	outb(sc->baseaddr + lpt_data, wdata + HNib); -	outb(sc->baseaddr + lpt_data, wdata + HNib); -	/* end-of-write */ -	outb(sc->baseaddr + lpt_data, EOC + wdata + HNib); -} - -/* - * Write the byte to DRAM via lpt_data; - * used for remote DMA write in mode 0 / 2 / 4 - */ -static __inline void -WrByteALToDRAM(struct rdp_softc *sc, u_char val) -{ - -	outb(sc->baseaddr + lpt_data, val & 0x0F); -	outb(sc->baseaddr + lpt_data, MkHi(val)); -} - -/* - * Write the byte to DRAM via lpt_control; - * used for remote DMA write in mode 1 / 3 / 5 - */ -static __inline void -WrByteALToDRAMA(struct rdp_softc *sc, u_char val) -{ - -	outb(sc->baseaddr + lpt_data, val & 0x0F); -	outb(sc->baseaddr + lpt_control, Ctrl_LNibRead | sc->irqenbit); -	outb(sc->baseaddr + lpt_data, val >> 4); -	outb(sc->baseaddr + lpt_control, Ctrl_HNibRead | sc->irqenbit); -} - -#if 0 /* they could be used for the RAM test */ -/* - * Write the u_short to DRAM via lpt_data; - * used for remote DMA write in mode 0 / 2 / 4 - */ -static __inline void -WrWordbxToDRAM(struct rdp_softc *sc, u_short val) -{ - -	outb(sc->baseaddr + lpt_data, val & 0x0F); -	val >>= 4; -	outb(sc->baseaddr + lpt_data, (val & 0x0F) + HNib); -	val >>= 4; -	outb(sc->baseaddr + lpt_data, val & 0x0F); -	val >>= 4; -	outb(sc->baseaddr + lpt_data, val + HNib); -} - - -/* - * Write the u_short to DRAM via lpt_control; - * used for remote DMA write in mode 1 / 3 / 5 - */ -static __inline void -WrWordbxToDRAMA(struct rdp_softc *sc, u_short val) -{ - -	outb(sc->baseaddr + lpt_data, val & 0x0F); -	outb(sc->baseaddr + lpt_control, Ctrl_LNibRead | sc->irqenbit); -	val >>= 4; -	outb(sc->baseaddr + lpt_data, (val & 0x0F) + HNib); -	outb(sc->baseaddr + lpt_control, Ctrl_HNibRead | sc->irqenbit); -	val >>= 4; -	outb(sc->baseaddr + lpt_data, val & 0x0F); -	outb(sc->baseaddr + lpt_control, Ctrl_LNibRead | sc->irqenbit); -	val >>= 4; -	outb(sc->baseaddr + lpt_data, val + HNib); -	outb(sc->baseaddr + lpt_control, Ctrl_HNibRead | sc->irqenbit); -} -#endif - - -/* - * Determine if the device is present - * - *   on entry: - * 	a pointer to an isa_device struct - *   on exit: - *	0 if device not found - *	or # of i/o addresses used (if found) - */ -static int -rdp_probe(struct isa_device *isa_dev) -{ -	int unit = isa_dev->id_unit; -	struct rdp_softc *sc = &rdp_softc[unit]; -	u_char b1, b2; -	intrmask_t irqmap[3]; -	u_char sval[3]; - -	if (unit < 0 || unit >= NRDP) -		return 0; - -	sc->baseaddr = isa_dev->id_iobase; -	if (isa_dev->id_flags & 1) -		sc->eeprom = EEPROM_74S288; -	/* else defaults to 93C46 */ -	if (isa_dev->id_flags & 2) -		sc->slow = 1; - -	/* let R/WB = A/DB = CSB = high to be ready for next r/w cycle */ -	outb(sc->baseaddr + lpt_data, 0xFF); -	/* DIR = 0 for write mode, IRQEN=0, SLCT=INIT=AUTOFEED=STB=high */ -	outb(sc->baseaddr + lpt_control, Ctrl_SelData); -	/* software reset */ -	WrNib(sc, CMR1 + HNib, MkHi(CMR1_RST)); -	DELAY(2000); -	/* is EPLC alive? */ -	b1 = RdNib(sc, CMR1); -	RdEnd(sc, CMR1); -	b2 = RdNib(sc, CMR2) & 0x0f; -	b2 |= RdNib(sc, CMR2 + HNib) << 4; -	RdEnd(sc, CMR2 + HNib); -	/* -	 * After the reset, we expect CMR1 & 7 to be 1 (rx buffer empty), -	 * and CMR2 & 0xf7 to be 0x20 (receive mode set to physical and -	 * broadcasts). -	 */ -	if (bootverbose) -		printf("rdp%d: CMR1 = %#x, CMR2 = %#x\n", unit, b1, b2); - -	if ((b1 & (CMR1_BUFE | CMR1_IRQ | CMR1_TRA)) != CMR1_BUFE -	    || (b2 & ~CMR2_IRQINV) != CMR2_AM_PB) -		return 0; - -	/* -	 * We have found something that could be a RTL 80[01]2, now -	 * see whether we can generate an interrupt. -	 */ -	disable_intr(); - -	/* -	 * Test whether our configured IRQ is working. -	 * -	 * Set to no acception mode + IRQout, then enable RxE + TxE, -	 * then cause RBER (by advancing the read pointer although -	 * the read buffer is empty) to generate an interrupt. -	 */ -	WrByte(sc, CMR2, CMR2_IRQOUT); -	WrNib(sc, CMR1 + HNib, MkHi(CMR1_TE | CMR1_RE)); -	WrNib(sc, CMR1, CMR1_RDPAC); -	DELAY(1000); - -	irqmap[0] = isa_irq_pending(); -	sval[0] = inb(sc->baseaddr + lpt_status); - -	/* allow IRQs to pass the parallel interface */ -	outb(sc->baseaddr + lpt_control, Ctrl_IRQEN + Ctrl_SelData); -	DELAY(1000); -	/* generate interrupt */ -	WrNib(sc, IMR + HNib, MkHi(ISR_RBER)); -	DELAY(1000); - -	irqmap[1] = isa_irq_pending(); -	sval[1] = inb(sc->baseaddr + lpt_status); - -	/* de-assert and disable IRQ */ -	WrNib(sc, IMR + HNib, MkHi(0)); -	(void)inb(sc->baseaddr + lpt_status); /* might be necessary to -						 clear IRQ */ -	DELAY(1000); -	irqmap[2] = isa_irq_pending(); -	sval[2] = inb(sc->baseaddr + lpt_status); - -	WrNib(sc, CMR1 + HNib, MkHi(0)); -	outb(sc->baseaddr + lpt_control, Ctrl_SelData); -	WrNib(sc, CMR2, CMR2_IRQINV); - -	enable_intr(); - -	if (bootverbose) -		printf("rdp%d: irq maps / lpt status " -		       "%#x/%#x - %#x/%#x - %#x/%#x (id_irq %#x)\n", -		       unit, irqmap[0], sval[0], irqmap[1], sval[1], -		       irqmap[2], sval[2], isa_dev->id_irq); - -	if ((irqmap[1] & isa_dev->id_irq) == 0) { -		printf("rdp%d: configured IRQ (%d) cannot be asserted " -		       "by device", -		       unit, ffs(isa_dev->id_irq) - 1); -		if (irqmap[1]) -			printf(" (probable IRQ: %d)", ffs(irqmap[1]) - 1); -		printf("\n"); -		return 0; -	} - -	/* -	 * XXX should do RAMtest here -	 */ - -	switch (sc->eeprom) { -	case EEPROM_93C46: -		if (rdp_gethwaddr_93c46(sc, sc->arpcom.ac_enaddr) == 0) { -			printf("rdp%d: failed to find a valid hardware " -			       "address in EEPROM\n", -			       unit); -			return 0; -		} -		break; - -	case EEPROM_74S288: -		rdp_gethwaddr_74s288(sc, sc->arpcom.ac_enaddr); -		break; -	} - -	return lpt_control + 1; -} - -/* - * Install interface into kernel networking data structures - */ -static int -rdp_attach(struct isa_device *isa_dev) -{ -	int unit = isa_dev->id_unit; -	struct rdp_softc *sc = &rdp_softc[unit]; -	struct ifnet *ifp = &sc->arpcom.ac_if; - -	isa_dev->id_ointr = rdpintr; - -	/* -	 * Reset interface -	 */ -	rdp_stop(sc); - -	if (!ifp->if_name) { -		/* -		 * Initialize ifnet structure -		 */ -		ifp->if_softc = sc; -		ifp->if_unit = unit; -		ifp->if_name = "rdp"; -		ifp->if_output = ether_output; -		ifp->if_start = rdp_start; -		ifp->if_ioctl = rdp_ioctl; -		ifp->if_watchdog = rdp_watchdog; -		ifp->if_init = rdp_init; -		ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; -		ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; - -		/* -		 * Attach the interface -		 */ -		if_attach(ifp); -		ether_ifattach(ifp); -	} - -	/* -	 * Print additional info when attached -	 */ -	printf("%s%d: RealTek RTL%s pocket ethernet, EEPROM %s, %s mode\n", -	       ifp->if_name, ifp->if_unit, -	       "8002",		/* hook for 8012 */ -	       sc->eeprom == EEPROM_93C46? "93C46": "74S288", -	       sc->slow? "slow": "fast"); -	printf("%s%d: address %6D\n", ifp->if_name, ifp->if_unit, -	       sc->arpcom.ac_enaddr, ":"); - -	/* -	 * If BPF is in the kernel, call the attach for it -	 */ -#if NBPFILTER > 0 -	bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); -#endif -	return 1; -} - -/* - * Reset interface. - */ -static void -rdp_reset(struct ifnet *ifp) -{ -	struct rdp_softc *sc = ifp->if_softc; -	int s; - -	s = splimp(); - -	/* -	 * Stop interface and re-initialize. -	 */ -	rdp_stop(sc); -	rdp_init(sc); - -	(void) splx(s); -} - -/* - * Take interface offline. - */ -static void -rdp_stop(struct rdp_softc *sc) -{ - -	sc->txbusy = sc->txbusy = 0; - -	/* disable printer interface interrupts */ -	sc->irqenbit = 0; -	outb(sc->baseaddr + lpt_control, Ctrl_SelData); -	outb(sc->baseaddr + lpt_data, 0xff); - -	/* reset the RTL 8002 */ -	WrNib(sc, CMR1 + HNib, MkHi(CMR1_RST)); -	DELAY(100); -} - -/* - * Device timeout/watchdog routine. Entered if the device neglects to - * generate an interrupt after a transmit has been started on it. - */ -static void -rdp_watchdog(struct ifnet *ifp) -{ - -	log(LOG_ERR, "rdp%d: device timeout\n", ifp->if_unit); -	ifp->if_oerrors++; - -	rdp_reset(ifp); -} - -/* - * Initialize device. - */ -static void -rdp_init(void *xsc) -{ -	struct rdp_softc *sc = xsc; -	struct ifnet *ifp = &sc->arpcom.ac_if; -	int i, s; -	u_char reg; - -	/* address not known */ -	if (TAILQ_EMPTY(&ifp->if_addrhead)) -		return; - -	s = splimp(); - -	ifp->if_timer = 0; - -	/* program ethernet ID into the chip */ -	for (i = 0, reg = IDR0; i < 6; i++, reg++) -		WrByte(sc, reg, sc->arpcom.ac_enaddr[i]); - -	/* set accept mode */ -	WrNib(sc, CMR2 + HNib, -	      MkHi((ifp->if_flags & IFF_PROMISC)? CMR2_AM_ALL: CMR2_AM_PB)); - -	/* enable tx and rx */ -	WrNib(sc, CMR1 + HNib, MkHi(CMR1_TE | CMR1_RE)); - -	/* allow interrupts to happen */ -	WrNib(sc, CMR2, CMR2_IRQOUT | CMR2_IRQINV); -	WrNib(sc, IMR, ISR_TOK | ISR_TER | ISR_ROK | ISR_RER); -	WrNib(sc, IMR + HNib, MkHi(ISR_RBER)); - -	/* allow IRQs to pass the parallel interface */ -	sc->irqenbit = Ctrl_IRQEN; -	outb(sc->baseaddr + lpt_control, sc->irqenbit + Ctrl_SelData); - -	/* clear all flags */ -	sc->txbusy = sc->txbuffered = 0; - -	/* -	 * Set 'running' flag, and clear output active flag. -	 */ -	ifp->if_flags |= IFF_RUNNING; -	ifp->if_flags &= ~IFF_OACTIVE; - -	/* -	 * ...and attempt to start output -	 */ -	rdp_start(ifp); - -	(void) splx(s); -} - -/* - * Start output on interface. - * We make two assumptions here: - *  1) that the current priority is set to splimp _before_ this code - *     is called *and* is returned to the appropriate priority after - *     return - *  2) that the IFF_OACTIVE flag is checked before this code is called - *     (i.e. that the output part of the interface is idle) - */ -static void -rdp_start(struct ifnet *ifp) -{ -	struct rdp_softc *sc = ifp->if_softc; -	struct mbuf *m; -	int len; - -outloop: - -	/* -	 * See if there is room to put another packet in the buffer. -	 */ -	if (sc->txbuffered) { -		/* -		 * No room. Indicate this to the outside world and exit. -		 */ -		ifp->if_flags |= IFF_OACTIVE; -		return; -	} -	IF_DEQUEUE(&ifp->if_snd, m); -	if (m == 0) { -		/* -		 * We are using the !OACTIVE flag to indicate to the outside -		 * world that we can accept an additional packet rather than -		 * that the transmitter is _actually_ active. Indeed, the -		 * transmitter may be active, but if we haven't filled all the -		 * buffers with data then we still want to accept more. -		 */ -		ifp->if_flags &= ~IFF_OACTIVE; -		return; -	} - -	/* -	 * Copy the mbuf chain into the transmit buffer -	 */ - -	len = rdp_write_mbufs(sc, m); -	if (len == 0) -		goto outloop; - -	/* ensure minimal valid ethernet length */ -	len = max(len, (ETHER_MIN_LEN-ETHER_CRC_LEN)); - -	/* -	 * Actually start the transceiver.  Set a timeout in case the -	 * Tx interrupt never arrives. -	 */ -	if (!sc->txbusy) { -		WrNib(sc, TBCR1, len >> 8); -		WrByte(sc, TBCR0, len & 0xff); -		WrNib(sc, CMR1, CMR1_TRA); -		sc->txbusy = 1; -		ifp->if_timer = 2; -	} else { -		sc->txbuffered = 1; -		sc->txsize = len; -	} - -	/* -	 * Tap off here if there is a bpf listener. -	 */ -#if NBPFILTER > 0 -	if (ifp->if_bpf) { -		bpf_mtap(ifp, m); -	} -#endif - -	m_freem(m); - -	/* -	 * Loop back to the top to possibly buffer more packets -	 */ -	goto outloop; -} - -/* - * Process an ioctl request. - */ -static int -rdp_ioctl(struct ifnet *ifp, IOCTL_CMD_T command, caddr_t data) -{ -	struct rdp_softc *sc = ifp->if_softc; -	int s, error = 0; - -	s = splimp(); - -	switch (command) { - -	case SIOCSIFADDR: -	case SIOCGIFADDR: -	case SIOCSIFMTU: -		error = ether_ioctl(ifp, command, data); -		break; - -	case SIOCSIFFLAGS: -		/* -		 * If the interface is marked up and stopped, then start it. -		 * If it is marked down and running, then stop it. -		 */ -		if (ifp->if_flags & IFF_UP) { -			if ((ifp->if_flags & IFF_RUNNING) == 0) -				rdp_init(sc); -		} else { -			if (ifp->if_flags & IFF_RUNNING) { -				rdp_stop(sc); -				ifp->if_flags &= ~IFF_RUNNING; -			} -		} - -#if NBPFILTER > 0 -		/* -		 * Promiscuous flag may have changed, propagage this -		 * to the NIC. -		 */ -		if (ifp->if_flags & IFF_UP) -			WrNib(sc, CMR2 + HNib, -			      MkHi((ifp->if_flags & IFF_PROMISC)? -				   CMR2_AM_ALL: CMR2_AM_PB)); - -#endif -		break; - -	case SIOCADDMULTI: -	case SIOCDELMULTI: -		/* -		 * Multicast list has changed; we don't support it. -		 */ -		error = ENOTTY; -		break; - -	default: -		error = EINVAL; -	} -	(void) splx(s); -	return (error); -} - -/* - * External interrupt service routine. - */ -void  -rdpintr(int unit) -{ -	struct rdp_softc *sc = rdp_softc + unit; -	struct ifnet *ifp = (struct ifnet *)sc; -	u_char isr, tsr, rsr, colls; - -	/* disable interrupts, so SD3 can be routed to the pin */ -	sc->irqenbit = 0; -	outb(sc->baseaddr + lpt_control, Ctrl_SelData); -	WrNib(sc, CMR2, CMR2_IRQINV); -	/* -	 * loop until there are no more new interrupts -	 */ -	for (;;) { -		isr = RdNib(sc, ISR); -		isr |= RdNib(sc, ISR + HNib) << 4; -		RdEnd(sc, ISR + HNib); - -		if (isr == 0) -			break; -#if DEBUG & 4 -		printf("rdp%d: ISR = %#x\n", unit, isr); -#endif - -		/* -		 * Clear the pending interrupt bits. -		 */ -		WrNib(sc, ISR, isr & 0x0f); -		if (isr & 0xf0) -			WrNib(sc, ISR + HNib, MkHi(isr)); - -		/* -		 * Handle transmitter interrupts. -		 */ -		if (isr & (ISR_TOK | ISR_TER)) { -			tsr = RdNib(sc, TSR); -			RdEnd(sc, TSR); -#if DEBUG & 4 -			if (isr & ISR_TER) -				printf("rdp%d: tsr %#x\n", unit, tsr); -#endif -			if (tsr & TSR_TABT) -				ifp->if_oerrors++; -			else -				/* -				 * Update total number of successfully -				 * transmitted packets. -				 */ -				ifp->if_opackets++; - -			if (tsr & TSR_COL) { -				colls = RdNib(sc, COLR); -				RdEnd(sc, COLR); -				ifp->if_collisions += colls; -			} - -			/* -			 * reset tx busy and output active flags -			 */ -			sc->txbusy = 0; -			ifp->if_flags &= ~IFF_OACTIVE; - -			/* -			 * If we had already queued up another packet, -			 * start sending it now. -			 */ -			if (sc->txbuffered) { -				WrNib(sc, TBCR1, sc->txsize >> 8); -				WrByte(sc, TBCR0, sc->txsize & 0xff); -				WrNib(sc, CMR1, CMR1_TRA); -				sc->txbusy = 1; -				sc->txbuffered = 0; -				ifp->if_timer = 2; -			} else { -				/* -				 * clear watchdog timer -				 */ -				ifp->if_timer = 0; -			} -			 -		} - -		/* -		 * Handle receiver interrupts -		 */ -		if (isr & (ISR_ROK | ISR_RER | ISR_RBER)) { -			rsr = RdNib(sc, RSR); -			rsr |= RdNib(sc, RSR + HNib) << 4; -			RdEnd(sc, RSR + HNib); -#if DEBUG & 4 -			if (isr & (ISR_RER | ISR_RBER)) -				printf("rdp%d: rsr %#x\n", unit, rsr); -#endif - -			if (rsr & (RSR_PUN | RSR_POV)) { -				printf("rdp%d: rsr %#x, resetting\n", -				       unit, rsr); -				rdp_reset(ifp); -				break; -			} - -			if (rsr & RSR_BUFO) -				/* -				 * CRC and FA errors are recorded in -				 * rdp_rint() on a per-packet basis -				 */ -				ifp->if_ierrors++; -			if (isr & (ISR_ROK | ISR_RER)) -				rdp_rint(sc); -		} - -		/* -		 * If it looks like the transmitter can take more data, -		 * attempt to start output on the interface. This is done -		 * after handling the receiver to give the receiver priority. -		 */ -		if ((ifp->if_flags & IFF_OACTIVE) == 0) -			rdp_start(ifp); - -	} -	/* re-enable interrupts */ -	WrNib(sc, CMR2, CMR2_IRQOUT | CMR2_IRQINV); -	sc->irqenbit = Ctrl_IRQEN; -	outb(sc->baseaddr + lpt_control, Ctrl_SelData + sc->irqenbit); -} - -/* - * Ethernet interface receiver interrupt. - */ -static void -rdp_rint(struct rdp_softc *sc) -{ -	struct ifnet *ifp = &sc->arpcom.ac_if; -	struct rdphdr rh; -	u_short len; -	size_t i; -	u_char *packet_ptr, b, status; -	int excessive_bad_pkts = 0; - -	/* -	 * Fetch the packets from the NIC's buffer. -	 */ -	for (;;) { -		b = RdNib(sc, CMR1); -		RdEnd(sc, CMR1); - -		if (b & CMR1_BUFE) -			/* no more packets */ -			break; - -		/* first, obtain the buffer header */ -		 -		outb(sc->baseaddr + lpt_data, MAR + EOC); /* prepare addr */ -		outb(sc->baseaddr + lpt_control, Ctrl_LNibRead); -		outb(sc->baseaddr + lpt_data, MAR + RdAddr + HNib); - -		packet_ptr = (u_char *)&rh; -		if (sc->slow) -			for (i = 0; i < sizeof rh; i++, packet_ptr++) -				*packet_ptr = RdByteA2(sc); -		else -			for (i = 0; i < sizeof rh; i++, packet_ptr++) -				*packet_ptr = RdByteA1(sc); - -		RdEnd(sc, MAR + HNib); -		outb(sc->baseaddr + lpt_control, Ctrl_SelData); - -		len = rh.pktlen - ETHER_CRC_LEN; -		status = rh.status; - -		if ((status & (RSR_ROK | RSR_CRC | RSR_FA)) != RSR_ROK || -		    len > (ETHER_MAX_LEN - ETHER_CRC_LEN) || -		    len < (ETHER_MIN_LEN - ETHER_CRC_LEN) || -		    len > MCLBYTES) { -#if DEBUG -			printf("rdp%d: bad packet in buffer, " -			       "len %d, status %#x\n", -			       ifp->if_unit, (int)len, (int)status); -#endif -			ifp->if_ierrors++; -			/* rx jump packet */ -			WrNib(sc, CMR1, CMR1_RDPAC); -			if (++excessive_bad_pkts > 5) { -				/* -				 * the chip seems to be stuck, we are -				 * probably seeing the same bad packet -				 * over and over again -				 */ -#if DEBUG -				printf("rdp%d: resetting due to an " -				       "excessive number of bad packets\n", -				       ifp->if_unit); -#endif -				rdp_reset(ifp); -				return; -			} -			continue; -		} - -		/* -		 * Go get packet. -		 */ -		excessive_bad_pkts = 0; -		rdp_get_packet(sc, len); -		ifp->if_ipackets++; -	} -} - -/* - * Retreive packet from NIC memory and send to the next level up via - * ether_input().  If there is a BPF listener, give a copy to BPF, - * too. - */ -static void -rdp_get_packet(struct rdp_softc *sc, unsigned len) -{ -	struct ether_header *eh; -	struct mbuf *m; -	u_char *packet_ptr; -	size_t s; - -	/* Allocate a header mbuf */ -	MGETHDR(m, M_DONTWAIT, MT_DATA); -	if (m == NULL) -		return; -	m->m_pkthdr.rcvif = &sc->arpcom.ac_if; -	m->m_pkthdr.len = m->m_len = len; - -	/* -	 * We always put the received packet in a single buffer - -	 * either with just an mbuf header or in a cluster attached -	 * to the header. The +2 is to compensate for the alignment -	 * fixup below. -	 */ -	if ((len + 2) > MHLEN) { -		/* Attach an mbuf cluster */ -		MCLGET(m, M_DONTWAIT); - -		/* Insist on getting a cluster */ -		if ((m->m_flags & M_EXT) == 0) { -			m_freem(m); -			return; -		} -	} - -	/* -	 * The +2 is to longword align the start of the real packet. -	 * This is important for NFS. -	 */ -	m->m_data += 2; -	eh = mtod(m, struct ether_header *); - -	/* -	 * Get packet, including link layer address, from interface. -	 */ -	outb(sc->baseaddr + lpt_control, Ctrl_LNibRead); -	outb(sc->baseaddr + lpt_data, RdAddr + MAR); - -	packet_ptr = (u_char *)eh; -	if (sc->slow) -		for (s = 0; s < len; s++, packet_ptr++) -			*packet_ptr = RdByteA2(sc); -	else -		for (s = 0; s < len; s++, packet_ptr++) -			*packet_ptr = RdByteA1(sc); - -	RdEnd(sc, MAR + HNib); -	outb(sc->baseaddr + lpt_control, Ctrl_SelData); -	WrNib(sc, CMR1, CMR1_RDPAC); - -#if NBPFILTER > 0 - -	/* -	 * Check if there's a BPF listener on this interface. If so, hand off -	 * the raw packet to bpf. -	 */ -	if (sc->arpcom.ac_if.if_bpf) { -		bpf_mtap(&sc->arpcom.ac_if, m); - -		/* -		 * Note that the interface cannot be in promiscuous mode if -		 * there are no BPF listeners.  And if we are in promiscuous -		 * mode, we have to check if this packet is really ours. -		 */ -		if ((sc->arpcom.ac_if.if_flags & IFF_PROMISC) && -		    bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, -			 sizeof(eh->ether_dhost)) != 0) { -			m_freem(m); -			return; -		} -	} -#endif - -	/* -	 * Remove link layer address. -	 */ -	m->m_pkthdr.len = m->m_len = len - sizeof(struct ether_header); -	m->m_data += sizeof(struct ether_header); - -	ether_input(&sc->arpcom.ac_if, eh, m); -	return; -} - -/* - * Write an mbuf chain to the NIC's tx buffer. - */ -static u_short -rdp_write_mbufs(struct rdp_softc *sc, struct mbuf *m) -{ -	u_short total_len; -	struct mbuf *mp; -	u_char *dp, b; -	int i; - -	/* First, count up the total number of bytes to copy */ -	for (total_len = 0, mp = m; mp; mp = mp->m_next) -		total_len += mp->m_len; - -	if (total_len == 0) -		return 0; - -	outb(sc->baseaddr + lpt_data, MAR | EOC); - -	/* -	 * Transfer the mbuf chain to the NIC memory. -	 */ -	if (sc->slow) { -		/* writing the first byte is complicated */ -		outb(sc->baseaddr + lpt_control, -		     Ctrl_LNibRead | sc->irqenbit); -		outb(sc->baseaddr + lpt_data, MAR | WrAddr); -		b = *(u_char *)m->m_data; -		outb(sc->baseaddr + lpt_data, (b & 0x0f) | 0x40); -		outb(sc->baseaddr + lpt_data, b & 0x0f); -		outb(sc->baseaddr + lpt_data, b >> 4); -		outb(sc->baseaddr + lpt_control, -		     Ctrl_HNibRead | sc->irqenbit); -		/* advance the mbuf pointer */ -		mp = m; -		m->m_len--; -		m->m_data++; -		/* write the remaining bytes */ -		while (m) { -			for (i = 0, dp = (u_char *)m->m_data; -			     i < m->m_len; -			     i++, dp++) -				WrByteALToDRAMA(sc, *dp); -			m = m->m_next; -		} -		/* -		 * restore old mbuf in case we have to hand it off to -		 * BPF again -		 */ -		m = mp; -		m->m_len++; -		m->m_data--; - -		/* the RTL 8002 requires an even byte-count remote DMA */ -		if (total_len & 1) -			WrByteALToDRAMA(sc, 0); -	} else { -		outb(sc->baseaddr + lpt_data, MAR | WrAddr); -		while (m) { -			for (i = 0, dp = (u_char *)m->m_data; -			     i < m->m_len; -			     i++, dp++) -				WrByteALToDRAM(sc, *dp); -			m = m->m_next; -		} - -		/* the RTL 8002 requires an even byte-count remote DMA */ -		if (total_len & 1) -			WrByteALToDRAM(sc, 0); -	} - -	outb(sc->baseaddr + lpt_data, 0xff); -	outb(sc->baseaddr + lpt_control, -	     Ctrl_HNibRead | Ctrl_SelData | sc->irqenbit); - -	return total_len; -} - -/* - * Read the designated ethernet hardware address out of a 93C46 - * (serial) EEPROM. - * Note that the 93C46 uses 16-bit words in big-endian notation. - */ -static int -rdp_gethwaddr_93c46(struct rdp_softc *sc, u_char *etheraddr) -{ -	int i, magic; -	size_t j = 0; -	u_short w; - -	WrNib(sc, CMR2, CMR2_PAGE | CMR2_IRQINV); /* select page 1 */ - -	/* -	 * The original RealTek packet driver had the ethernet address -	 * starting at EEPROM address 0.  Other vendors seem to have -	 * gone `creative' here -- while they didn't do anything else -	 * than changing a few strings in the entire driver, compared -	 * to the RealTek version, they also moved out the ethernet -	 * address to a different location in the EEPROM, so the -	 * original RealTek driver won't work correctly with them, and -	 * vice versa.  Sounds pretty cool, eh?  $@%&! -	 * -	 * Anyway, we walk through the EEPROM, until we find some -	 * allowable value based upon our table of IEEE OUI assignments. -	 */ -	for (i = magic = 0; magic < 3 && i < 32; i++) { -		/* read cmd (+ 6 bit address) */ -		rdp_93c46_cmd(sc, 0x180 + i, 10); -		w = rdp_93c46_read(sc); -		switch (magic) { -		case 0: -			for (j = 0; -			     j < sizeof allowed_ouis / sizeof(u_short); -			     j++) -				if (w == allowed_ouis[j]) { -					etheraddr[0] = (w >> 8) & 0xff; -					etheraddr[1] = w & 0xff; -					magic++; -					break; -				} -			break; - -		case 1: -			/* -			 * If the first two bytes have been 00:00, we -			 * discard the match iff the next two bytes -			 * are also 00:00, so we won't get fooled by -			 * an EEPROM that has been filled with zeros. -			 * This in theory would disallow 64 K of legal -			 * addresses assigned to Xerox, but it's -			 * almost certain that those addresses haven't -			 * been used for RTL80[01]2 chips anyway. -			 */ -			if ((etheraddr[0] | etheraddr[1]) == 0 && w == 0) { -				magic--; -				break; -			} - -			etheraddr[2] = (w >> 8) & 0xff; -			etheraddr[3] = w & 0xff; -			magic++; -			break; - -		case 2: -			etheraddr[4] = (w >> 8) & 0xff; -			etheraddr[5] = w & 0xff; -			magic++; -			break; -		} -	} - -	WrNib(sc, CMR2, CMR2_IRQINV);	/* back to page 0 */ - -	return magic == 3; -} - -/* - * Read the designated ethernet hardware address out of a 74S288 - * EEPROM. - * - * This is untested, since i haven't seen any adapter actually using - * a 74S288.  In the RTL 8012, only the serial EEPROM (94C46) is - * supported anymore. - */ -static void -rdp_gethwaddr_74s288(struct rdp_softc *sc, u_char *etheraddr) -{ -	int i; -	u_char b; - -	WrNib(sc, CMR2, CMR2_PAGE | CMR2_IRQINV); /* select page 1 */ - -	for (i = 0; i < 6; i++) { -		WrNib(sc, PCMR, i & 0x0f); /* lower 4 bit of addr */ -		WrNib(sc, PCMR + HNib, HNib + 4); /* upper 2 bit addr + /CS */ -		WrNib(sc, PCMR + HNib, HNib); /* latch data now */ -		b = RdNib(sc, PDR) & 0x0f; -		b |= (RdNib(sc, PDR + HNib) & 0x0f) << 4; -		etheraddr[i] = b; -	} - -	RdEnd(sc, PDR + HNib); -	WrNib(sc, CMR2, CMR2_IRQINV);	/* reselect page 0 */ -} - -/* - * Send nbits of data (starting with MSB) out to the 93c46 as a - * command.  Assumes register page 1 has already been selected. - */ -static void -rdp_93c46_cmd(struct rdp_softc *sc, u_short data, unsigned nbits) -{ -	u_short mask = 1 << (nbits - 1); -	unsigned i; -	u_char b; - -#if DEBUG & 2 -	printf("rdp_93c46_cmd(): "); -#endif -	for (i = 0; i < nbits; i++, mask >>= 1) { -		b = HNib + PCMR_SK + PCMR_CS; -		if (data & mask) -			b += PCMR_DO; -#if DEBUG & 2 -		printf("%d", b & 1); -#endif -		WrNib(sc, PCMR + HNib, b); -		DELAY(1); -		WrNib(sc, PCMR + HNib, b & ~PCMR_SK); -		DELAY(1); -	} -#if DEBUG & 2 -	printf("\n"); -#endif -} - -/* - * Read one word of data from the 93c46.  Actually, we have to read - * 17 bits, and discard the very first bit.  Assumes register page 1 - * to be selected as well. - */ -static u_short -rdp_93c46_read(struct rdp_softc *sc) -{ -	u_short data = 0; -	u_char b; -	int i; - -#if DEBUG & 2 -	printf("rdp_93c46_read(): "); -#endif -	for (i = 0; i < 17; i++) { -		WrNib(sc, PCMR + HNib, PCMR_SK + PCMR_CS + HNib); -		DELAY(1); -		WrNib(sc, PCMR + HNib, PCMR_CS + HNib); -		DELAY(1); -		b = RdNib(sc, PDR); -		data <<= 1; -		if (b & 1) -			data |= 1; -#if DEBUG & 2 -		printf("%d", b & 1); -#endif -		RdEnd(sc, PDR); -		DELAY(1); -	} - -#if DEBUG & 2 -	printf("\n"); -#endif -	/* end of cycle */ -	WrNib(sc, PCMR + HNib, PCMR_SK + HNib); -	DELAY(1); - -	return data; -} | 
