Subject: PLIP for -current
To: None <port-i386@NetBSD.ORG>
From: Martin Husemann <martin@rumolt.teuto.de>
List: port-i386
Date: 10/19/1997 11:32:52
Here is an updated version of the PLIP support Matthias Pfaller and I ported
from port-pc532 to port-i386.

This takes care of the latest lpt.c split into dev/ic/lpt.c and 
dev/isa/lpt_isa.c and fixes a few of the gross hacks in the code.
Still waiting for generic soft interrupt allocation...

This works for me, YMMV.


Martin


diff -rNc2 ../sys/arch/i386/isa/icu.s ./arch/i386/isa/icu.s
*** ../sys/arch/i386/isa/icu.s	Thu Apr  3 14:23:05 1997
--- ./arch/i386/isa/icu.s	Sun Oct 19 12:18:47 1997
***************
*** 178,181 ****
--- 178,185 ----
  	DONET(NETISR_PPP, _pppintr)
  #endif
+ #include "lpt.h"
+ #if NLPT > 0
+ 	DONET(NETISR_PLIP, _plipsoftint)
+ #endif
  	movl	%ebx,_cpl
  	jmp	%esi
diff -rNc2 ../sys/dev/ic/lpt.c ./dev/ic/lpt.c
*** ../sys/dev/ic/lpt.c	Wed Oct 15 14:35:43 1997
--- ./dev/ic/lpt.c	Sun Oct 19 12:51:28 1997
***************
*** 2,5 ****
--- 2,7 ----
  
  /*
+  * Copyright (c) 1994 Matthias Pfaller.
+  * Copyright (c) 1994 Poul-Henning Kamp
   * Copyright (c) 1993, 1994 Charles Hannum.
   * Copyright (c) 1990 William F. Jolitz, TeleMuse
***************
*** 69,72 ****
--- 71,96 ----
  #include <machine/intr.h>
  
+ #if defined(INET) && defined(PLIP)
+ #include "bpfilter.h"
+ #include <sys/mbuf.h>
+ #include <sys/socket.h>
+ 
+ #include <net/if.h>
+ #include <net/if_dl.h>
+ #include <net/if_types.h>
+ #include <net/if_ether.h>
+ #include <net/netisr.h>
+ 
+ #include <netinet/in.h>
+ #include <netinet/in_systm.h>
+ #include <netinet/in_var.h>
+ #include <netinet/ip.h>
+ #include <netinet/if_inarp.h>
+ #if NBPFILTER > 0
+ #include <sys/time.h>
+ #include <net/bpf.h>
+ #endif
+ #endif
+ 
  #include <dev/ic/lptreg.h>
  #include <dev/ic/lptvar.h>
***************
*** 87,90 ****
--- 111,165 ----
  #endif
  
+ #if defined(INET) && defined(PLIP)
+ #if defined(COMPAT_PLIP10)
+ #define	PLIPMTU		1600				/* Linux 1.0.x */
+ #elif defined(COMPAT_PLIP11)
+ #define	PLIPMTU		(ETHERMTU - ifp->if_hdrlen)	/* Linux 1.1.x */
+ #else
+ #define PLIPMTU		ETHERMTU			/* Linux 1.3.x */
+ #endif
+ 
+ #ifndef PLIPMXSPIN1		/* DELAY factor for the plip# interfaces */
+ #define	PLIPMXSPIN1	50000	/* Spinning for remote intr to happen */
+ #endif
+ 
+ #ifndef PLIPMXSPIN2		/* DELAY factor for the plip# interfaces */
+ #define	PLIPMXSPIN2	50000	/* Spinning for remote handshake to happen */
+ #endif
+ 
+ #ifndef PLIPMXERRS		/* Max errors before !RUNNING */
+ #define	PLIPMXERRS	50
+ #endif
+ #ifndef PLIPMXRETRY
+ #define PLIPMXRETRY	20	/* Max number of retransmits */
+ #endif
+ #ifndef PLIPRETRY
+ #define PLIPRETRY	hz/50	/* Time between retransmits */
+ #endif
+ 
+ #define STABILIZE(iot, ioh, io) ({ \
+ 		int v1, v2; \
+ 		v2 = bus_space_read_1(iot, ioh, io); \
+ 		do { \
+ 			v1 = v2; \
+ 			v2 = bus_space_read_1(iot, ioh, io); \
+ 		} while (v1 != v2); \
+ 		v2; \
+ 	})
+ #endif
+  
+ #if defined(INET) && defined(PLIP)
+ /* Functions for the plip# interface */
+ static void	plipattach __P((struct lpt_softc *));
+ static void	plipinput __P((struct lpt_softc *));
+ static int	plipioctl __P((struct ifnet *, u_long, caddr_t));
+ static void	plipoutput __P((void *));
+ static int	plipreceive __P((struct lpt_softc *, u_char *, int));
+ static void	pliprxenable __P((void *));
+ void		plipsoftint __P((void));
+ static void	plipstart __P((struct ifnet *));
+ static int	pliptransmit __P((struct lpt_softc *, u_char *, int));
+ #endif
+ 
  /* XXX does not belong here */
  cdev_decl(lpt);
***************
*** 110,113 ****
--- 185,192 ----
  
  	bus_space_write_1(iot, ioh, lpt_control, LPC_NINIT);
+ 
+ #if defined(INET) && defined(PLIP)
+ 	plipattach(sc);
+ #endif
  }
  
***************
*** 150,153 ****
--- 229,236 ----
  	if (sc->sc_state)
  		return EBUSY;
+ #if defined(INET) && defined(PLIP)
+ 	if (sc->sc_ethercom.ec_if.if_flags & IFF_UP)
+ 		return EBUSY;
+ #endif
  
  	sc->sc_state = LPT_INIT;
***************
*** 376,379 ****
--- 459,475 ----
  		return 0;
  #endif
+   
+ #if defined(INET) && defined(PLIP)
+ 	if (sc->sc_ethercom.ec_if.if_flags & IFF_UP) {
+ 		if ((sc->sc_control & LPC_IENABLE) == 0)
+ 			return 0;	/* dispose spurious interrupt */
+ 
+ 		bus_space_write_1(iot, ioh, lpt_control, sc->sc_control &= ~LPC_IENABLE);
+ 		sc->sc_pending |= PLIP_IPENDING;
+ 		/*softintr(sc->sc_ifsoftint);*/
+ 		schednetisr(NETISR_PLIP);
+ 		return 0;
+ 	}
+ #endif
  
  	/* is printer online and ready for output */
***************
*** 417,418 ****
--- 513,990 ----
  	return error;
  }
+ 
+ #if defined(INET) && defined(PLIP)
+ 
+ static void
+ plipattach(sc)
+ 	struct lpt_softc *sc;
+ {
+ 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
+ 	u_int8_t myaddr[ETHER_ADDR_LEN];
+ 
+ 	sc->sc_ifbuf = NULL;
+ 	sprintf(ifp->if_xname, "plip%d", sc->sc_dev.dv_unit);
+ 	bzero(myaddr, sizeof(myaddr));
+ 	ifp->if_softc = sc;
+ 	ifp->if_start = plipstart;
+ 	ifp->if_ioctl = plipioctl;
+ 	ifp->if_watchdog = 0;
+ 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
+ 
+ 	if_attach(ifp);
+ 	ether_ifattach(ifp, myaddr);
+ 	ifp->if_mtu = PLIPMTU;
+ 
+ #if NBPFILTER > 0
+ 	bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
+ #endif                 
+ 	/*
+ 	 * We hope to get Charle's MI softint establish RSN - the
+ 	 * current hack involves patching icu.s and hardcoding
+ 	 * the softinterupts in a complete unrelated peace
+ 	 * of code....
+ 	sc->sc_ifsoftint = isa_intr_establish(SOFTINT, 0, ISA_IPL_NET,
+ 				plipsoftint, sc);
+ 	 */
+ }
+ 
+ /*
+  * Process an ioctl request.
+  */
+ static int
+ plipioctl(ifp, cmd, data)
+ 	struct ifnet *ifp;
+ 	u_long cmd;
+ 	caddr_t data;
+ {
+ 	struct proc *p = curproc;
+ 	struct lpt_softc *sc = (struct lpt_softc *) ifp->if_softc;
+ 	u_char control = sc->sc_control;
+ 	struct ifaddr *ifa = (struct ifaddr *)data;
+ 	struct ifreq *ifr = (struct ifreq *)data; 
+ 	bus_space_tag_t iot = sc->sc_iot;
+ 	bus_space_handle_t ioh = sc->sc_ioh;
+ 	struct sockaddr_dl *sdl;
+ 	int error = 0;
+ 
+ 	switch (cmd) {
+ 	case SIOCSIFFLAGS:
+ 		if (((ifp->if_flags & IFF_UP) == 0) &&
+ 		    (ifp->if_flags & IFF_RUNNING)) {
+ 		        ifp->if_flags &= ~IFF_RUNNING;
+ 			control = LPC_SELECT | LPC_NINIT;
+ 			bus_space_write_1(iot, ioh, lpt_control, control);
+ 
+ 			if (sc->sc_ifbuf)
+ 				free(sc->sc_ifbuf, M_DEVBUF);
+ 			sc->sc_ifbuf = NULL;
+ 		}
+ 		if (((ifp->if_flags & IFF_UP)) &&
+ 		    ((ifp->if_flags & IFF_RUNNING) == 0)) {
+ 			if (sc->sc_state) {
+ 				error = EBUSY;
+ 				break;
+ 			}
+ 			if (sc->sc_ih == 0) {
+ 				error = EINVAL;
+ 				break;
+ 			}
+ 			if (!sc->sc_ifbuf)
+ 				sc->sc_ifbuf =
+ 					malloc(ifp->if_mtu + ifp->if_hdrlen,
+ 					       M_DEVBUF, M_WAITOK);
+ 		        ifp->if_flags |= IFF_RUNNING;
+ 			bus_space_write_1(iot, ioh, lpt_control, control & ~LPC_IENABLE);
+ 			bus_space_write_1(iot, ioh, lpt_data, 0);
+ 			bus_space_write_1(iot, ioh, lpt_control, control |= LPC_IENABLE);
+ 		}
+ 		break;
+ 
+ 	case SIOCSIFADDR:
+ 		sdl = ifp->if_sadl;
+ 		if (ifa->ifa_addr->sa_family == AF_INET) {
+ 			if (!sc->sc_ifbuf)
+ 				sc->sc_ifbuf =
+ 					malloc(PLIPMTU + ifp->if_hdrlen,
+ 					       M_DEVBUF, M_WAITOK);
+ 			LLADDR(sdl)[0] = 0xfc;
+ 			LLADDR(sdl)[1] = 0xfc;
+ 			bcopy((caddr_t)&IA_SIN(ifa)->sin_addr,
+ 			      (caddr_t)&LLADDR(sdl)[2], 4);
+ #if defined(COMPAT_PLIP10)
+ 			if (ifp->if_flags & IFF_LINK0) {
+ 				int i;
+ 				LLADDR(sdl)[0] = 0xfd;
+ 				LLADDR(sdl)[1] = 0xfd;
+ 				for (i = sc->sc_adrcksum = 0; i < 5; i++)
+ 					sc->sc_adrcksum += LLADDR(sdl)[i];
+ 				sc->sc_adrcksum *= 2;
+ 			}
+ #endif
+ 			ifp->if_flags |= IFF_RUNNING | IFF_UP;
+ 			bus_space_write_1(iot, ioh, lpt_control, control & ~LPC_IENABLE);
+ 			bus_space_write_1(iot, ioh, lpt_data, 0);
+ 			bus_space_write_1(iot, ioh, lpt_control, control |= LPC_IENABLE);
+ 			arp_ifinit(ifp, ifa);
+ 		} else
+ 			error = EAFNOSUPPORT;
+ 		break;
+ 
+ 	case SIOCAIFADDR:
+ 	case SIOCDIFADDR:
+ 	case SIOCSIFDSTADDR:
+ 		if (ifa->ifa_addr->sa_family != AF_INET)
+ 			error = EAFNOSUPPORT;
+ 		break;
+ 
+ 	case SIOCSIFMTU:
+         	if ((error = suser(p->p_ucred, &p->p_acflag)))
+             		return(error);
+ 		if (ifp->if_mtu != ifr->ifr_metric) {
+ 		        ifp->if_mtu = ifr->ifr_metric;
+ 			if (sc->sc_ifbuf) {
+ 				free(sc->sc_ifbuf, M_DEVBUF);
+ 				sc->sc_ifbuf =
+ 					malloc(ifp->if_mtu + ifp->if_hdrlen,
+ 					       M_DEVBUF, M_WAITOK);
+ 			}
+ 		}
+ 		break;
+ 
+ 	default:
+ 		error = EINVAL;
+ 	}
+ 	sc->sc_control = control;
+ 	return (error);
+ }
+ 
+ void
+ plipsoftint()
+ {
+ 	/* while the MI softint framework isn't there, we check
+ 	   check all lpt devices */
+ 	struct device *dev;
+ 
+ 	for (dev = alldevs.tqh_first; dev; dev = dev->dv_list.tqe_next) {
+ 		if (dev->dv_cfdata->cf_driver == &lpt_cd) {
+ 			int pending;
+ 			struct lpt_softc *sc = (struct lpt_softc*)dev;
+ 
+ 			pending = sc->sc_pending;
+ 			while (sc->sc_pending & PLIP_IPENDING) {
+ 				pending |= sc->sc_pending;
+ 				sc->sc_pending = 0;
+ 				plipinput(sc);
+ 			}
+ 
+ 			if (pending & PLIP_OPENDING)
+ 				plipoutput(sc);
+ 		}
+ 	}
+ }
+ 
+ static int
+ plipreceive(sc, buf, len)
+ 	struct lpt_softc *sc;
+ 	u_char *buf;
+ 	int len;
+ {
+ 	bus_space_tag_t iot = sc->sc_iot;
+ 	bus_space_handle_t ioh = sc->sc_ioh;
+ 	int i;
+ 	u_char cksum = 0, cl, ch;
+ 
+ 	while (len--) {
+ 		i = PLIPMXSPIN2;
+ 		while (((cl = STABILIZE(iot, ioh, lpt_status)) & LPS_NBSY) != 0)
+ 			if (i-- < 0) return -1;
+ 		cl = (cl >> 3) & 0x0f;
+ 		bus_space_write_1(iot, ioh, lpt_data, 0x11);
+ 		while (((ch = STABILIZE(iot, ioh, lpt_status)) & LPS_NBSY) == 0)
+ 			if (i-- < 0) return -1;
+ 		cl |= (ch << 1) & 0xf0;
+ 		bus_space_write_1(iot, ioh, lpt_data, 0x01);
+ 		cksum += (*buf++ = cl);
+ 	}
+ 	return(cksum);
+ }
+ 
+ static void
+ pliprxenable(arg)
+ 	void *arg;
+ {
+ 	struct lpt_softc *sc = arg;
+ 	bus_space_tag_t iot = sc->sc_iot;
+ 	bus_space_handle_t ioh = sc->sc_ioh;
+ 	bus_space_write_1(iot, ioh, lpt_control, sc->sc_control |= LPC_IENABLE);
+ }
+ 
+ static void
+ plipinput(sc)
+ 	struct lpt_softc *sc;
+ {
+ 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
+ 	bus_space_tag_t iot = sc->sc_iot;
+ 	bus_space_handle_t ioh = sc->sc_ioh;
+ 	struct mbuf *m;
+ 	struct ether_header *eh;
+ 	u_char *p = sc->sc_ifbuf, minibuf[4];
+ 	int s, len, cksum;
+ 
+ #ifndef PLIP_NO_INCOLL
+ 	if (!(STABILIZE(iot, ioh, lpt_status) & LPS_NACK)) {
+ 		bus_space_write_1(iot, ioh, lpt_control, sc->sc_control |= LPC_IENABLE);
+ 		ifp->if_collisions++;
+ 		return;
+ 	}
+ #endif
+ 	bus_space_write_1(iot, ioh, lpt_data, 0x01);
+ 	bus_space_write_1(iot, ioh, lpt_control, sc->sc_control &= ~LPC_IENABLE);
+ 
+ 	if (sc->sc_ifierrs)
+ 		untimeout(pliprxenable, sc);
+ 
+ #if defined(COMPAT_PLIP10)
+ 	if (ifp->if_flags & IFF_LINK0) {
+ 		int c;
+ 		if (plipreceive(sc, minibuf, 3) < 0) goto err;
+ 		len = (minibuf[1] << 8) | minibuf[2];
+ 		if (len > (ifp->if_mtu + ifp->if_hdrlen)) goto err;
+ 
+ 		switch (minibuf[0]) {
+ 		case 0xfc:
+ 			p[0] = p[ 6] = LLADDR(ifp->if_sadl)[0];
+ 			p[1] = p[ 7] = LLADDR(ifp->if_sadl)[1];
+ 			p[2] = p[ 8] = LLADDR(ifp->if_sadl)[2];
+ 			p[3] = p[ 9] = LLADDR(ifp->if_sadl)[3];
+ 			p[4] = p[10] = LLADDR(ifp->if_sadl)[4];
+ 			p += 5;
+ 			if ((cksum = plipreceive(sc, p, 1)) < 0) goto err;
+ 			p += 6;
+ 			if ((c = plipreceive(sc, p, len - 11)) < 0) goto err;
+ 			cksum += c + sc->sc_adrcksum;
+ 			c = p[1]; p[1] = p[2]; p[2] = c;
+ 			cksum &= 0xff;
+ 			break;
+ 		case 0xfd:
+ 			if ((cksum = plipreceive(sc, p, len)) < 0) goto err;
+ 			break;
+ 		default:
+ 			goto err;
+ 		}
+ 	} else
+ #endif
+ 	{
+ 		if (plipreceive(sc, minibuf, 2) < 0) goto err;
+ 		len = (minibuf[1] << 8) | minibuf[0];
+ 		if (len > (ifp->if_mtu + ifp->if_hdrlen)) {
+ 			log(LOG_NOTICE, "%s: packet > MTU\n", ifp->if_xname);
+ 			goto err;
+ 		}
+ 		if ((cksum = plipreceive(sc, p, len)) < 0) goto err;
+ 	}
+ 	
+ 	if (plipreceive(sc, minibuf, 1) < 0) goto err;
+ 	if (cksum != minibuf[0]) {
+ 		log(LOG_NOTICE, "%s: checksum error\n", ifp->if_xname);
+ 		goto err;
+ 	}
+ 	bus_space_write_1(iot, ioh, lpt_data, 0x00);
+ 
+ 	s = splimp();
+ 	if ((m = m_devget(sc->sc_ifbuf, len, 0, ifp, NULL)) != NULL) {
+ 		/* We assume that the header fit entirely in one mbuf. */
+ 		eh = mtod(m, struct ether_header *);
+ #if NBPFILTER > 0
+ 		/*
+ 		 * Check if there's a BPF listener on this interface.
+ 		 * If so, hand off the raw packet to bpf.
+ 		 */
+ 		if (ifp->if_bpf) {
+ 			bpf_mtap(ifp->if_bpf, m);
+ 		}
+ #endif
+ 		/* We assume the header fit entirely in one mbuf. */
+ 		m_adj(m, sizeof(struct ether_header));
+ 		ether_input(ifp, eh, m);
+ 	}
+ 	splx(s);
+ 	sc->sc_ifierrs = 0;
+ 	ifp->if_ipackets++;
+ 	bus_space_write_1(iot, ioh, lpt_control, sc->sc_control |= LPC_IENABLE);
+ 	return;
+ 
+ err:
+ 	bus_space_write_1(iot, ioh, lpt_data, 0x00);
+ 
+ 	if (sc->sc_ifierrs < PLIPMXERRS) {
+ 		if (sc->sc_ifierrs > 4 && (STABILIZE(iot, ioh, lpt_status) & LPS_NBSY)) {
+ 			/* Avoid interrupt nesting ... */
+ 			sc->sc_ifierrs = PLIPMXERRS - 1;
+ 		}
+ 		bus_space_write_1(iot, ioh, lpt_control, sc->sc_control |= LPC_IENABLE);
+ 	} else {
+ 		/* We are not able to send or receive anything for now,
+ 		 * so stop wasting our time and leave the interrupt
+ 		 * disabled.
+ 		 */
+ 		if (sc->sc_ifierrs == PLIPMXERRS)
+ 			log(LOG_NOTICE, "%s: rx hard error\n", ifp->if_xname);
+ 		/* But we will retry from time to time. */
+ 		timeout(pliprxenable, sc, PLIPRETRY * 10);
+ 	}
+ 	ifp->if_ierrors++;
+ 	sc->sc_ifierrs++;
+ 	return;
+ }
+ 
+ static int
+ pliptransmit(sc, buf, len)
+ 	struct lpt_softc *sc;
+ 	u_char *buf;
+ 	int len;
+ {
+ 	bus_space_tag_t iot = sc->sc_iot;
+ 	bus_space_handle_t ioh = sc->sc_ioh;
+ 	int i;
+ 	u_char cksum = 0, c;
+ 
+ 	while (len--) {
+ 		i = PLIPMXSPIN2;
+ 		cksum += (c = *buf++);
+ 		while ((STABILIZE(iot, ioh, lpt_status) & LPS_NBSY) == 0)
+ 			if (i-- < 0) return -1;
+ 		bus_space_write_1(iot, ioh, lpt_data, c & 0x0f);
+ 		bus_space_write_1(iot, ioh, lpt_data, (c & 0x0f) | 0x10);
+ 		c >>= 4;
+ 		while ((STABILIZE(iot, ioh, lpt_status) & LPS_NBSY) != 0)
+ 			if (i-- < 0) return -1;
+ 		bus_space_write_1(iot, ioh, lpt_data, c | 0x10);
+ 		bus_space_write_1(iot, ioh, lpt_data, c);
+ 	}
+ 	return(cksum);
+ }
+ 
+ /*
+  * Setup output on interface.
+  */
+ static void
+ plipstart(ifp)
+ 	struct ifnet *ifp;
+ {
+ 	struct lpt_softc *sc = (struct lpt_softc *) ifp->if_softc;
+ 	sc->sc_pending |= PLIP_OPENDING;
+ 	/*softintr(sc->sc_ifsoftint);*/
+ 	schednetisr(NETISR_PLIP);
+ }
+ 
+ static void
+ plipoutput(arg)
+ 	void *arg;
+ {
+ 	struct lpt_softc *sc = arg;
+ 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
+ 	bus_space_tag_t iot = sc->sc_iot;
+ 	bus_space_handle_t ioh = sc->sc_ioh;
+ 	struct mbuf *m0, *m;
+ 	u_char minibuf[4], cksum;
+ 	int len, i, s;
+ 
+ 	if (ifp->if_flags & IFF_OACTIVE)
+ 		return;
+ 	ifp->if_flags |= IFF_OACTIVE;
+ 
+ 	if (sc->sc_ifoerrs)
+ 		untimeout(plipoutput, sc);
+ 
+ 	for (;;) {
+ 		s = splnet();
+ 		IF_DEQUEUE(&ifp->if_snd, m0);
+ 		splx(s);
+ 		if (!m0)
+ 			break;
+ 
+ #if NBPFILTER > 0
+ 		if (ifp->if_bpf)
+ 			bpf_mtap(ifp->if_bpf, m0);
+ #endif
+ 
+ 		len = m0->m_pkthdr.len;
+ 
+ #if defined(COMPAT_PLIP10)
+ 		if (ifp->if_flags & IFF_LINK0) {
+ 			minibuf[0] = 3;
+ 			minibuf[1] = 0xfd;
+ 			minibuf[2] = len >> 8;
+ 			minibuf[3] = len;
+ 		} else
+ #endif
+ 		{
+ 			minibuf[0] = 2;
+ 			minibuf[1] = len;
+ 			minibuf[2] = len >> 8;
+ 		}
+ 
+ 		/* Trigger remote interrupt */
+ 		i = PLIPMXSPIN1;
+ 		do {
+ 			if (sc->sc_pending & PLIP_IPENDING) {
+ 				bus_space_write_1(iot, ioh, lpt_data, 0x00);
+ 				sc->sc_pending = 0;
+ 				plipinput(sc);
+ 				i = PLIPMXSPIN1;
+ 			} else if (i-- < 0)
+ 				goto retry;
+ 			/* Retrigger remote interrupt */
+ 			bus_space_write_1(iot, ioh, lpt_data, 0x08);
+ 		} while ((STABILIZE(iot, ioh, lpt_status) & LPS_NERR) == 0);
+ 		bus_space_write_1(iot, ioh, lpt_control, sc->sc_control &= ~LPC_IENABLE);
+ 		if (pliptransmit(sc, minibuf + 1, minibuf[0]) < 0) goto retry;
+ 		for (cksum = 0, m = m0; m; m = m->m_next) {
+ 			i = pliptransmit(sc, mtod(m, u_char *), m->m_len);
+ 			if (i < 0) goto retry;
+ 			cksum += i;
+ 		}
+ 		if (pliptransmit(sc, &cksum, 1) < 0) goto retry;
+ 		i = PLIPMXSPIN2;
+ 		while ((STABILIZE(iot, ioh, lpt_status) & LPS_NBSY) == 0)
+ 			if (i-- < 0) goto retry;
+ 		sc->sc_pending = 0;
+ 		bus_space_write_1(iot, ioh, lpt_data, 0x00);
+ 
+ 		ifp->if_opackets++;
+ 		ifp->if_obytes += len + 4;
+ 		sc->sc_ifoerrs = 0;
+ 		m_freem(m0);
+ 		bus_space_write_1(iot, ioh, lpt_control, sc->sc_control |= LPC_IENABLE);
+ 	}
+ 	ifp->if_flags &= ~IFF_OACTIVE;
+ 	return;
+ 
+ retry:
+ 	if (STABILIZE(iot, ioh, lpt_status) & LPS_NACK)
+ 		ifp->if_collisions++;
+ 	else
+ 		ifp->if_oerrors++;
+ 
+ 	ifp->if_flags &= ~IFF_OACTIVE;
+ 	bus_space_write_1(iot, ioh, lpt_data, 0x00);
+ 
+ 	if ((ifp->if_flags & (IFF_RUNNING | IFF_UP)) == (IFF_RUNNING | IFF_UP)
+ 	    && sc->sc_ifoerrs < PLIPMXRETRY) {
+ 		s = splnet();
+ 		IF_PREPEND(&ifp->if_snd, m0);
+ 		splx(s);
+ 		timeout(plipoutput, sc, PLIPRETRY);
+ 	} else {
+ 		/* we are not able to send this... give up for now */
+ 		if (sc->sc_ifoerrs == PLIPMXRETRY) {
+ 			log(LOG_NOTICE, "%s: tx hard error\n", ifp->if_xname);
+ 		}
+ 		m_freem(m0);
+ 	}
+ 	bus_space_write_1(iot, ioh, lpt_control, sc->sc_control |= LPC_IENABLE);
+ 	sc->sc_ifoerrs++;
+ }
+ 
+ #endif
diff -rNc2 ../sys/dev/ic/lptvar.h ./dev/ic/lptvar.h
*** ../sys/dev/ic/lptvar.h	Wed Oct 15 14:35:44 1997
--- ./dev/ic/lptvar.h	Sun Oct 19 12:26:29 1997
***************
*** 59,62 ****
--- 59,63 ----
  struct lpt_softc {
  	struct device sc_dev;
+ 
  	void *sc_ih;
  	size_t sc_count;
***************
*** 76,79 ****
--- 77,95 ----
  	u_char sc_control;
  	u_char sc_laststatus;
+ 
+ #if defined(INET) && defined(PLIP)
+ 	struct	ethercom sc_ethercom;
+ 	u_char		*sc_ifbuf;
+ 	int		sc_ifierrs;	/* consecutive input errors */
+ 	int		sc_ifoerrs;	/* consecutive output errors */
+ 	int		sc_ifsoftint;	/* i/o software interrupt */
+ 	volatile int	sc_pending;	/* interrputs pending */
+ #define PLIP_IPENDING	1
+ #define PLIP_OPENDING	2
+ 
+ #if defined(COMPAT_PLIP10)
+ 	u_char		sc_adrcksum;
+ #endif
+ #endif
  };
  
diff -rNc2 ../sys/dev/isa/files.isa ./dev/isa/files.isa
*** ../sys/dev/isa/files.isa	Thu Oct 16 15:49:03 1997
--- ./dev/isa/files.isa	Sun Oct 19 12:16:23 1997
***************
*** 56,60 ****
  # PC-style parallel ports (XXX what chip?)
  # XXX chip driver should be defined elsewhere
! device	lpt
  file	dev/ic/lpt.c			lpt needs-flag
  
--- 56,60 ----
  # PC-style parallel ports (XXX what chip?)
  # XXX chip driver should be defined elsewhere
! device	lpt: ifnet, ether, arp	# XXX - "ifnet, ether, arp" only if option PLIP
  file	dev/ic/lpt.c			lpt needs-flag
  
diff -rNc2 ../sys/dev/isa/lpt_isa.c ./dev/isa/lpt_isa.c
*** ../sys/dev/isa/lpt_isa.c	Wed Oct 15 14:35:55 1997
--- ./dev/isa/lpt_isa.c	Sun Oct 19 12:39:08 1997
***************
*** 69,72 ****
--- 69,78 ----
  #include <machine/intr.h>
  
+ #if defined(INET) && defined(PLIP)
+ #include <sys/socket.h>
+ #include <net/if.h>
+ #include <net/if_ether.h>
+ #endif
+ 
  #include <dev/isa/isavar.h>
  #include <dev/ic/lptreg.h>
***************
*** 242,246 ****
  	if (ia->ia_irq != IRQUNK)
  		lsc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
! 		    IPL_TTY, lptintr, lsc);
  }
  
--- 248,252 ----
  	if (ia->ia_irq != IRQUNK)
  		lsc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
! 		    IPL_NONE, lptintr, lsc);
  }
  
diff -rNc2 ../sys/net/netisr.h ./net/netisr.h
*** ../sys/net/netisr.h	Thu Apr  3 14:26:56 1997
--- ./net/netisr.h	Sun Oct 19 12:17:25 1997
***************
*** 64,67 ****
--- 64,68 ----
  #define NETISR_NATM	27		/* same as AF_NATM */
  #define NETISR_PPP	28		/* for PPP processing */
+ #define	NETISR_PLIP	29		/* for PLIP processing */
  
  #define	schednetisr(anisr)	{ netisr |= 1<<(anisr); setsoftnet(); }