if_plip.c revision 184896
1170159Sariff/*-
2170159Sariff * Copyright (c) 1997 Poul-Henning Kamp
3170159Sariff * All rights reserved.
4170159Sariff *
5170159Sariff * Redistribution and use in source and binary forms, with or without
6170159Sariff * modification, are permitted provided that the following conditions
7170159Sariff * are met:
8170159Sariff * 1. Redistributions of source code must retain the above copyright
9170159Sariff *    notice, this list of conditions and the following disclaimer.
10170159Sariff * 2. Redistributions in binary form must reproduce the above copyright
11170159Sariff *    notice, this list of conditions and the following disclaimer in the
12170159Sariff *    documentation and/or other materials provided with the distribution.
13170159Sariff *
14170159Sariff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15170159Sariff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16170159Sariff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17170159Sariff * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18170159Sariff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19170159Sariff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20170159Sariff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21170159Sariff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22170159Sariff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23170159Sariff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24170159Sariff * SUCH DAMAGE.
25170159Sariff *
26170159Sariff *	From Id: lpt.c,v 1.55.2.1 1996/11/12 09:08:38 phk Exp
27170159Sariff */
28170159Sariff
29170159Sariff#include <sys/cdefs.h>
30170159Sariff__FBSDID("$FreeBSD: head/sys/dev/ppbus/if_plip.c 184896 2008-11-12 22:14:05Z jhb $");
31170159Sariff
32170159Sariff/*
33170159Sariff * Parallel port TCP/IP interfaces added.  I looked at the driver from
34170159Sariff * MACH but this is a complete rewrite, and btw. incompatible, and it
35170159Sariff * should perform better too.  I have never run the MACH driver though.
36170159Sariff *
37170159Sariff * This driver sends two bytes (0x08, 0x00) in front of each packet,
38170159Sariff * to allow us to distinguish another format later.
39170159Sariff *
40170159Sariff * Now added a Linux/Crynwr compatibility mode which is enabled using
41170159Sariff * IF_LINK0 - Tim Wilkinson.
42170159Sariff *
43170159Sariff * TODO:
44170159Sariff *    Make HDLC/PPP mode, use IF_LLC1 to enable.
45170159Sariff *
46170159Sariff * Connect the two computers using a Laplink parallel cable to use this
47170159Sariff * feature:
48170159Sariff *
49170159Sariff *      +----------------------------------------+
50170159Sariff * 	|A-name	A-End	B-End	Descr.	Port/Bit |
51170159Sariff *      +----------------------------------------+
52170159Sariff *	|DATA0	2	15	Data	0/0x01   |
53170159Sariff *	|-ERROR	15	2	   	1/0x08   |
54170159Sariff *      +----------------------------------------+
55170159Sariff *	|DATA1	3	13	Data	0/0x02	 |
56170159Sariff *	|+SLCT	13	3	   	1/0x10   |
57170159Sariff *      +----------------------------------------+
58170159Sariff *	|DATA2	4	12	Data	0/0x04   |
59170159Sariff *	|+PE	12	4	   	1/0x20   |
60170159Sariff *      +----------------------------------------+
61170159Sariff *	|DATA3	5	10	Strobe	0/0x08   |
62170159Sariff *	|-ACK	10	5	   	1/0x40   |
63170159Sariff *      +----------------------------------------+
64170159Sariff *	|DATA4	6	11	Data	0/0x10   |
65170159Sariff *	|BUSY	11	6	   	1/~0x80  |
66170159Sariff *      +----------------------------------------+
67170159Sariff *	|GND	18-25	18-25	GND	-        |
68170159Sariff *      +----------------------------------------+
69170159Sariff *
70170159Sariff * Expect transfer-rates up to 75 kbyte/sec.
71170159Sariff *
72170159Sariff * If GCC could correctly grok
73170159Sariff *	register int port asm("edx")
74170159Sariff * the code would be cleaner
75170159Sariff *
76170159Sariff * Poul-Henning Kamp <phk@freebsd.org>
77170159Sariff */
78170159Sariff
79170159Sariff/*
80170159Sariff * Update for ppbus, PLIP support only - Nicolas Souchu
81170159Sariff */
82170159Sariff
83170159Sariff#include "opt_plip.h"
84170159Sariff
85170159Sariff#include <sys/param.h>
86170159Sariff#include <sys/systm.h>
87170159Sariff#include <sys/module.h>
88170159Sariff#include <sys/bus.h>
89170159Sariff#include <sys/mbuf.h>
90170159Sariff#include <sys/socket.h>
91170159Sariff#include <sys/sockio.h>
92170159Sariff#include <sys/kernel.h>
93170159Sariff#include <sys/malloc.h>
94170159Sariff
95170159Sariff#include <machine/bus.h>
96170159Sariff#include <machine/resource.h>
97170159Sariff#include <sys/rman.h>
98170159Sariff
99170159Sariff#include <net/if.h>
100170159Sariff#include <net/if_types.h>
101170159Sariff#include <net/netisr.h>
102170159Sariff
103170159Sariff#include <netinet/in.h>
104170159Sariff#include <netinet/in_var.h>
105170159Sariff
106170159Sariff#include <net/bpf.h>
107170159Sariff
108170159Sariff#include <dev/ppbus/ppbconf.h>
109170159Sariff#include "ppbus_if.h"
110170159Sariff#include <dev/ppbus/ppbio.h>
111170159Sariff
112170159Sariff#ifndef LPMTU			/* MTU for the lp# interfaces */
113170159Sariff#define	LPMTU		1500
114170159Sariff#endif
115170159Sariff
116170159Sariff#ifndef LPMAXSPIN1		/* DELAY factor for the lp# interfaces */
117170159Sariff#define	LPMAXSPIN1	8000   /* Spinning for remote intr to happen */
118170159Sariff#endif
119170159Sariff
120170159Sariff#ifndef LPMAXSPIN2		/* DELAY factor for the lp# interfaces */
121170159Sariff#define	LPMAXSPIN2	500	/* Spinning for remote handshake to happen */
122170159Sariff#endif
123170159Sariff
124170159Sariff#ifndef LPMAXERRS		/* Max errors before !RUNNING */
125170159Sariff#define	LPMAXERRS	100
126170159Sariff#endif
127170159Sariff
128170159Sariff#define CLPIPHDRLEN	14	/* We send dummy ethernet addresses (two) + packet type in front of packet */
129170159Sariff#define	CLPIP_SHAKE	0x80	/* This bit toggles between nibble reception */
130170159Sariff#define MLPIPHDRLEN	CLPIPHDRLEN
131170159Sariff
132170159Sariff#define LPIPHDRLEN	2	/* We send 0x08, 0x00 in front of packet */
133170159Sariff#define	LPIP_SHAKE	0x40	/* This bit toggles between nibble reception */
134170159Sariff#if !defined(MLPIPHDRLEN) || LPIPHDRLEN > MLPIPHDRLEN
135170159Sariff#define MLPIPHDRLEN	LPIPHDRLEN
136170159Sariff#endif
137170159Sariff
138170159Sariff#define	LPIPTBLSIZE	256	/* Size of octet translation table */
139170159Sariff
140170159Sariff#define lprintf		if (lptflag) printf
141170159Sariff
142170159Sariff#ifdef PLIP_DEBUG
143170159Sariffstatic int volatile lptflag = 1;
144170159Sariff#else
145170159Sariffstatic int volatile lptflag = 0;
146170159Sariff#endif
147170159Sariff
148170159Sariffstruct lp_data {
149170159Sariff	struct  ifnet	*sc_ifp;
150170159Sariff	device_t	sc_dev;
151170159Sariff	u_char		*sc_ifbuf;
152170159Sariff	int		sc_iferrs;
153170159Sariff
154170159Sariff	struct resource *res_irq;
155170159Sariff};
156170159Sariff
157170159Sariff/* Tables for the lp# interface */
158170159Sariffstatic u_char *txmith;
159170159Sariff#define txmitl (txmith + (1 * LPIPTBLSIZE))
160170159Sariff#define trecvh (txmith + (2 * LPIPTBLSIZE))
161170159Sariff#define trecvl (txmith + (3 * LPIPTBLSIZE))
162170159Sariff
163170159Sariffstatic u_char *ctxmith;
164170159Sariff#define ctxmitl (ctxmith + (1 * LPIPTBLSIZE))
165170159Sariff#define ctrecvh (ctxmith + (2 * LPIPTBLSIZE))
166170159Sariff#define ctrecvl (ctxmith + (3 * LPIPTBLSIZE))
167170159Sariff
168170159Sariff/* Functions for the lp# interface */
169170159Sariffstatic int lpinittables(void);
170170159Sariffstatic int lpioctl(struct ifnet *, u_long, caddr_t);
171170159Sariffstatic int lpoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
172170159Sariff	struct rtentry *);
173170159Sariffstatic void lp_intr(void *);
174170159Sariff
175170159Sariff#define DEVTOSOFTC(dev) \
176170159Sariff	((struct lp_data *)device_get_softc(dev))
177170159Sariff
178170159Sariffstatic devclass_t lp_devclass;
179170159Sariff
180170159Sariffstatic void
181170159Sarifflp_identify(driver_t *driver, device_t parent)
182170159Sariff{
183170159Sariff	device_t dev;
184170159Sariff
185170159Sariff	dev = device_find_child(parent, "plip", -1);
186170159Sariff	if (!dev)
187170159Sariff		BUS_ADD_CHILD(parent, 0, "plip", -1);
188170159Sariff}
189170159Sariff
190170159Sariffstatic int
191170159Sarifflp_probe(device_t dev)
192170159Sariff{
193170159Sariff
194170159Sariff	device_set_desc(dev, "PLIP network interface");
195170159Sariff
196170159Sariff	return (0);
197170159Sariff}
198170159Sariff
199170159Sariffstatic int
200170159Sarifflp_attach(device_t dev)
201170159Sariff{
202170159Sariff	struct lp_data *lp = DEVTOSOFTC(dev);
203170159Sariff	struct ifnet *ifp;
204170159Sariff	int rid = 0;
205170159Sariff
206170159Sariff	lp->sc_dev = dev;
207170159Sariff
208170159Sariff	/*
209170159Sariff	 * Reserve the interrupt resource.  If we don't have one, the
210170159Sariff	 * attach fails.
211170159Sariff	 */
212170159Sariff	lp->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
213170159Sariff	    RF_SHAREABLE);
214170159Sariff	if (lp->res_irq == 0) {
215170159Sariff		device_printf(dev, "cannot reserve interrupt, failed.\n");
216170159Sariff		return (ENXIO);
217170159Sariff	}
218170159Sariff
219170159Sariff	ifp = lp->sc_ifp = if_alloc(IFT_PARA);
220170159Sariff	if (ifp == NULL) {
221170159Sariff		return (ENOSPC);
222170159Sariff	}
223170159Sariff
224170159Sariff	ifp->if_softc = lp;
225170159Sariff	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
226170159Sariff	ifp->if_mtu = LPMTU;
227170159Sariff	ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST |
228170159Sariff	    IFF_NEEDSGIANT;
229170159Sariff	ifp->if_ioctl = lpioctl;
230170159Sariff	ifp->if_output = lpoutput;
231170159Sariff	ifp->if_hdrlen = 0;
232170159Sariff	ifp->if_addrlen = 0;
233170159Sariff	ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
234170159Sariff	if_attach(ifp);
235170159Sariff
236170159Sariff	bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
237170159Sariff
238170159Sariff	return (0);
239170159Sariff}
240170159Sariff/*
241170159Sariff * Build the translation tables for the LPIP (BSD unix) protocol.
242170159Sariff * We don't want to calculate these nasties in our tight loop, so we
243170159Sariff * precalculate them when we initialize.
244170159Sariff */
245170159Sariffstatic int
246170159Sarifflpinittables(void)
247170159Sariff{
248170159Sariff	int i;
249170159Sariff
250170159Sariff	if (txmith == NULL)
251170159Sariff		txmith = malloc(4 * LPIPTBLSIZE, M_DEVBUF, M_NOWAIT);
252170159Sariff
253170159Sariff	if (txmith == NULL)
254170159Sariff		return (1);
255170159Sariff
256170159Sariff	if (ctxmith == NULL)
257170159Sariff	ctxmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT);
258170159Sariff
259170159Sariff	if (ctxmith == NULL)
260170159Sariff		return (1);
261170159Sariff
262170159Sariff	for (i = 0; i < LPIPTBLSIZE; i++) {
263170159Sariff		ctxmith[i] = (i & 0xF0) >> 4;
264170159Sariff		ctxmitl[i] = 0x10 | (i & 0x0F);
265170159Sariff		ctrecvh[i] = (i & 0x78) << 1;
266170159Sariff		ctrecvl[i] = (i & 0x78) >> 3;
267170159Sariff	}
268170159Sariff
269170159Sariff	for (i = 0; i < LPIPTBLSIZE; i++) {
270170159Sariff		txmith[i] = ((i & 0x80) >> 3) | ((i & 0x70) >> 4) | 0x08;
271170159Sariff		txmitl[i] = ((i & 0x08) << 1) | (i & 0x07);
272170159Sariff		trecvh[i] = ((~i) & 0x80) | ((i & 0x38) << 1);
273170159Sariff		trecvl[i] = (((~i) & 0x80) >> 4) | ((i & 0x38) >> 3);
274170159Sariff	}
275170159Sariff
276170159Sariff	return (0);
277170159Sariff}
278170159Sariff
279170159Sariff/*
280170159Sariff * Process an ioctl request.
281170159Sariff */
282170159Sariffstatic int
283170159Sarifflpioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
284170159Sariff{
285170159Sariff	struct lp_data *sc = ifp->if_softc;
286170159Sariff	device_t dev = sc->sc_dev;
287170159Sariff	device_t ppbus = device_get_parent(dev);
288170159Sariff	struct ifaddr *ifa = (struct ifaddr *)data;
289170159Sariff	struct ifreq *ifr = (struct ifreq *)data;
290170159Sariff	u_char *ptr;
291170159Sariff	void *ih;
292170159Sariff	int error;
293170159Sariff
294170159Sariff	switch (cmd) {
295170159Sariff	case SIOCSIFDSTADDR:
296170159Sariff	case SIOCAIFADDR:
297170159Sariff	case SIOCSIFADDR:
298170159Sariff		if (ifa->ifa_addr->sa_family != AF_INET)
299170159Sariff			return (EAFNOSUPPORT);
300170159Sariff
301170159Sariff		ifp->if_flags |= IFF_UP;
302170159Sariff		/* FALLTHROUGH */
303170159Sariff	case SIOCSIFFLAGS:
304170159Sariff		if ((!(ifp->if_flags & IFF_UP)) &&
305170159Sariff		    (ifp->if_drv_flags & IFF_DRV_RUNNING)) {
306170159Sariff
307170159Sariff			ppb_wctr(ppbus, 0x00);
308170159Sariff			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
309170159Sariff
310170159Sariff			/* IFF_UP is not set, try to release the bus anyway */
311170159Sariff			ppb_release_bus(ppbus, dev);
312170159Sariff			break;
313170159Sariff		}
314170159Sariff		if (((ifp->if_flags & IFF_UP)) &&
315170159Sariff		    (!(ifp->if_drv_flags & IFF_DRV_RUNNING))) {
316170159Sariff
317170159Sariff			/* XXX
318170159Sariff			 * Should the request be interruptible?
319170159Sariff			 */
320170159Sariff			if ((error = ppb_request_bus(ppbus, dev, PPB_WAIT |
321170159Sariff			    PPB_INTR)))
322170159Sariff				return (error);
323170159Sariff
324170159Sariff			/* Now IFF_UP means that we own the bus */
325170159Sariff			ppb_set_mode(ppbus, PPB_COMPATIBLE);
326170159Sariff
327170159Sariff			if (lpinittables()) {
328170159Sariff				ppb_release_bus(ppbus, dev);
329170159Sariff				return (ENOBUFS);
330170159Sariff			}
331170159Sariff
332170159Sariff			sc->sc_ifbuf = malloc(sc->sc_ifp->if_mtu + MLPIPHDRLEN,
333170159Sariff			    M_DEVBUF, M_WAITOK);
334170159Sariff			if (sc->sc_ifbuf == NULL) {
335170159Sariff				ppb_release_bus(ppbus, dev);
336170159Sariff				return (ENOBUFS);
337170159Sariff			}
338170159Sariff
339170159Sariff			/*
340170159Sariff			 * Attach our interrupt handler.  It is
341170159Sariff			 * detached later when the bus is released.
342170159Sariff			 */
343170159Sariff			if ((error = bus_setup_intr(dev, sc->res_irq,
344170159Sariff			    INTR_TYPE_NET, NULL, lp_intr, dev, &ih))) {
345170159Sariff				ppb_release_bus(ppbus, dev);
346170159Sariff				return (error);
347170159Sariff			}
348170159Sariff
349170159Sariff			ppb_wctr(ppbus, IRQENABLE);
350170159Sariff			ifp->if_drv_flags |= IFF_DRV_RUNNING;
351170159Sariff		}
352170159Sariff		break;
353170159Sariff
354170159Sariff	case SIOCSIFMTU:
355170159Sariff		ptr = sc->sc_ifbuf;
356170159Sariff		sc->sc_ifbuf = malloc(ifr->ifr_mtu + MLPIPHDRLEN, M_DEVBUF,
357170159Sariff		    M_NOWAIT);
358170159Sariff		if (sc->sc_ifbuf == NULL) {
359170159Sariff			sc->sc_ifbuf = ptr;
360170159Sariff			return (ENOBUFS);
361170159Sariff		}
362170159Sariff		if (ptr)
363170159Sariff			free(ptr, M_DEVBUF);
364170159Sariff		sc->sc_ifp->if_mtu = ifr->ifr_mtu;
365170159Sariff		break;
366170159Sariff
367170159Sariff	case SIOCGIFMTU:
368170159Sariff		ifr->ifr_mtu = sc->sc_ifp->if_mtu;
369170159Sariff		break;
370170159Sariff
371170159Sariff	case SIOCADDMULTI:
372170159Sariff	case SIOCDELMULTI:
373170159Sariff		if (ifr == 0) {
374170159Sariff			return (EAFNOSUPPORT);		/* XXX */
375170159Sariff		}
376170159Sariff		switch (ifr->ifr_addr.sa_family) {
377170159Sariff		case AF_INET:
378170159Sariff			break;
379170159Sariff		default:
380170159Sariff			return (EAFNOSUPPORT);
381170159Sariff		}
382170159Sariff		break;
383170159Sariff
384170159Sariff	case SIOCGIFMEDIA:
385170159Sariff		/*
386170159Sariff		 * No ifmedia support at this stage; maybe use it
387170159Sariff		 * in future for eg. protocol selection.
388170159Sariff		 */
389170159Sariff		return (EINVAL);
390170159Sariff
391170159Sariff	default:
392170159Sariff		lprintf("LP:ioctl(0x%lx)\n", cmd);
393170159Sariff		return (EINVAL);
394170159Sariff	}
395170159Sariff	return (0);
396170159Sariff}
397170159Sariff
398170159Sariffstatic __inline int
399170159Sariffclpoutbyte(u_char byte, int spin, device_t ppbus)
400170159Sariff{
401170159Sariff
402170159Sariff	ppb_wdtr(ppbus, ctxmitl[byte]);
403170159Sariff	while (ppb_rstr(ppbus) & CLPIP_SHAKE)
404170159Sariff		if (--spin == 0) {
405170159Sariff			return (1);
406170159Sariff		}
407170159Sariff	ppb_wdtr(ppbus, ctxmith[byte]);
408170159Sariff	while (!(ppb_rstr(ppbus) & CLPIP_SHAKE))
409170159Sariff		if (--spin == 0) {
410170159Sariff			return (1);
411170159Sariff		}
412170159Sariff	return (0);
413170159Sariff}
414170159Sariff
415170159Sariffstatic __inline int
416170159Sariffclpinbyte(int spin, device_t ppbus)
417170159Sariff{
418170159Sariff	u_char c, cl;
419170159Sariff
420170159Sariff	while((ppb_rstr(ppbus) & CLPIP_SHAKE))
421170159Sariff		if (!--spin) {
422170159Sariff			return (-1);
423170159Sariff		}
424170159Sariff	cl = ppb_rstr(ppbus);
425170159Sariff	ppb_wdtr(ppbus, 0x10);
426170159Sariff
427170159Sariff	while(!(ppb_rstr(ppbus) & CLPIP_SHAKE))
428170159Sariff		if (!--spin) {
429170159Sariff			return (-1);
430170159Sariff		}
431170159Sariff	c = ppb_rstr(ppbus);
432170159Sariff	ppb_wdtr(ppbus, 0x00);
433170159Sariff
434170159Sariff	return (ctrecvl[cl] | ctrecvh[c]);
435170159Sariff}
436170159Sariff
437170159Sariffstatic void
438170159Sarifflptap(struct ifnet *ifp, struct mbuf *m)
439170159Sariff{
440170159Sariff	u_int32_t af = AF_INET;
441170159Sariff
442170159Sariff	bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m);
443170159Sariff}
444170159Sariff
445170159Sariffstatic void
446170159Sarifflp_intr(void *arg)
447170159Sariff{
448170159Sariff	device_t dev = (device_t)arg;
449170159Sariff        device_t ppbus = device_get_parent(dev);
450170159Sariff	struct lp_data *sc = DEVTOSOFTC(dev);
451170159Sariff	int len, s, j;
452170159Sariff	u_char *bp;
453170159Sariff	u_char c, cl;
454170159Sariff	struct mbuf *top;
455170159Sariff
456170159Sariff	s = splhigh();
457170159Sariff
458170159Sariff	if (sc->sc_ifp->if_flags & IFF_LINK0) {
459170159Sariff
460170159Sariff		/* Ack. the request */
461170159Sariff		ppb_wdtr(ppbus, 0x01);
462170159Sariff
463170159Sariff		/* Get the packet length */
464170159Sariff		j = clpinbyte(LPMAXSPIN2, ppbus);
465170159Sariff		if (j == -1)
466170159Sariff			goto err;
467170159Sariff		len = j;
468170159Sariff		j = clpinbyte(LPMAXSPIN2, ppbus);
469170159Sariff		if (j == -1)
470170159Sariff			goto err;
471170159Sariff		len = len + (j << 8);
472170159Sariff		if (len > sc->sc_ifp->if_mtu + MLPIPHDRLEN)
473170159Sariff			goto err;
474170159Sariff
475170159Sariff		bp = sc->sc_ifbuf;
476170159Sariff
477170159Sariff		while (len--) {
478170159Sariff			j = clpinbyte(LPMAXSPIN2, ppbus);
479170159Sariff			if (j == -1) {
480170159Sariff				goto err;
481170159Sariff			}
482170159Sariff			*bp++ = j;
483170159Sariff		}
484170159Sariff
485170159Sariff		/* Get and ignore checksum */
486170159Sariff		j = clpinbyte(LPMAXSPIN2, ppbus);
487170159Sariff		if (j == -1) {
488170159Sariff			goto err;
489170159Sariff		}
490170159Sariff
491170159Sariff		len = bp - sc->sc_ifbuf;
492170159Sariff		if (len <= CLPIPHDRLEN)
493170159Sariff			goto err;
494170159Sariff
495170159Sariff		sc->sc_iferrs = 0;
496170159Sariff
497170159Sariff		len -= CLPIPHDRLEN;
498170159Sariff		sc->sc_ifp->if_ipackets++;
499170159Sariff		sc->sc_ifp->if_ibytes += len;
500170159Sariff		top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, sc->sc_ifp,
501170159Sariff		    0);
502170159Sariff		if (top) {
503170159Sariff			if (bpf_peers_present(sc->sc_ifp->if_bpf))
504170159Sariff				lptap(sc->sc_ifp, top);
505170159Sariff
506170159Sariff			/* mbuf is free'd on failure. */
507170159Sariff			netisr_queue(NETISR_IP, top);
508170159Sariff		}
509170159Sariff		goto done;
510170159Sariff	}
511170159Sariff	while ((ppb_rstr(ppbus) & LPIP_SHAKE)) {
512170159Sariff		len = sc->sc_ifp->if_mtu + LPIPHDRLEN;
513170159Sariff		bp  = sc->sc_ifbuf;
514170159Sariff		while (len--) {
515170159Sariff
516170159Sariff			cl = ppb_rstr(ppbus);
517170159Sariff			ppb_wdtr(ppbus, 8);
518170159Sariff
519170159Sariff			j = LPMAXSPIN2;
520170159Sariff			while((ppb_rstr(ppbus) & LPIP_SHAKE))
521170159Sariff				if (!--j)
522170159Sariff					goto err;
523170159Sariff
524170159Sariff			c = ppb_rstr(ppbus);
525170159Sariff			ppb_wdtr(ppbus, 0);
526170159Sariff
527170159Sariff			*bp++= trecvh[cl] | trecvl[c];
528170159Sariff
529170159Sariff			j = LPMAXSPIN2;
530170159Sariff			while (!((cl = ppb_rstr(ppbus)) & LPIP_SHAKE)) {
531170159Sariff				if (cl != c &&
532170159Sariff				    (((cl = ppb_rstr(ppbus)) ^ 0xb8) & 0xf8) ==
533170159Sariff				    (c & 0xf8))
534170159Sariff					goto end;
535170159Sariff				if (!--j)
536170159Sariff					goto err;
537170159Sariff			}
538170159Sariff		}
539170159Sariff
540170159Sariff	end:
541170159Sariff		len = bp - sc->sc_ifbuf;
542170159Sariff		if (len <= LPIPHDRLEN)
543170159Sariff			goto err;
544170159Sariff
545170159Sariff		sc->sc_iferrs = 0;
546170159Sariff
547170159Sariff		len -= LPIPHDRLEN;
548170159Sariff		sc->sc_ifp->if_ipackets++;
549170159Sariff		sc->sc_ifp->if_ibytes += len;
550170159Sariff		top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, sc->sc_ifp,
551170159Sariff		    0);
552170159Sariff		if (top) {
553170159Sariff			if (bpf_peers_present(sc->sc_ifp->if_bpf))
554170159Sariff				lptap(sc->sc_ifp, top);
555170159Sariff
556170159Sariff			/* mbuf is free'd on failure. */
557170159Sariff			netisr_queue(NETISR_IP, top);
558170159Sariff		}
559170159Sariff	}
560170159Sariff	goto done;
561170159Sariff
562170159Sariff    err:
563170159Sariff	ppb_wdtr(ppbus, 0);
564170159Sariff	lprintf("R");
565170159Sariff	sc->sc_ifp->if_ierrors++;
566170159Sariff	sc->sc_iferrs++;
567170159Sariff
568170159Sariff	/*
569170159Sariff	 * We are not able to send receive anything for now,
570170159Sariff	 * so stop wasting our time
571170159Sariff	 */
572170159Sariff	if (sc->sc_iferrs > LPMAXERRS) {
573170159Sariff		if_printf(sc->sc_ifp, "Too many errors, Going off-line.\n");
574170159Sariff		ppb_wctr(ppbus, 0x00);
575170159Sariff		sc->sc_ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
576170159Sariff		sc->sc_iferrs = 0;
577170159Sariff	}
578170159Sariff
579170159Sariff    done:
580170159Sariff	splx(s);
581170159Sariff}
582170159Sariff
583170159Sariffstatic __inline int
584170159Sarifflpoutbyte (u_char byte, int spin, device_t ppbus)
585170159Sariff{
586170159Sariff
587170159Sariff	ppb_wdtr(ppbus, txmith[byte]);
588170159Sariff	while (!(ppb_rstr(ppbus) & LPIP_SHAKE))
589170159Sariff		if (--spin == 0)
590170159Sariff			return (1);
591170159Sariff	ppb_wdtr(ppbus, txmitl[byte]);
592170159Sariff	while (ppb_rstr(ppbus) & LPIP_SHAKE)
593170159Sariff		if (--spin == 0)
594170159Sariff			return (1);
595170159Sariff	return (0);
596170159Sariff}
597170159Sariff
598170159Sariffstatic int
599170159Sarifflpoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
600170159Sariff    struct rtentry *rt)
601170159Sariff{
602170159Sariff	struct lp_data *sc = ifp->if_softc;
603170159Sariff	device_t dev = sc->sc_dev;
604170159Sariff	device_t ppbus = device_get_parent(dev);
605170159Sariff	int s, err;
606170159Sariff	struct mbuf *mm;
607170159Sariff	u_char *cp = "\0\0";
608170159Sariff	u_char chksum = 0;
609170159Sariff	int count = 0;
610170159Sariff	int i, len, spin;
611170159Sariff
612170159Sariff	/* We need a sensible value if we abort */
613170159Sariff	cp++;
614170159Sariff	ifp->if_drv_flags |= IFF_DRV_RUNNING;
615170159Sariff
616170159Sariff	err = 1;		/* assume we're aborting because of an error */
617170159Sariff
618170159Sariff	s = splhigh();
619170159Sariff
620170159Sariff	/* Suspend (on laptops) or receive-errors might have taken us offline */
621170159Sariff	ppb_wctr(ppbus, IRQENABLE);
622170159Sariff
623170159Sariff	if (ifp->if_flags & IFF_LINK0) {
624170159Sariff		if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) {
625170159Sariff			lprintf("&");
626170159Sariff			lp_intr(dev);
627170159Sariff		}
628170159Sariff
629170159Sariff		/* Alert other end to pending packet */
630170159Sariff		spin = LPMAXSPIN1;
631170159Sariff		ppb_wdtr(ppbus, 0x08);
632170159Sariff		while ((ppb_rstr(ppbus) & 0x08) == 0)
633170159Sariff			if (--spin == 0) {
634170159Sariff				goto nend;
635170159Sariff			}
636170159Sariff
637170159Sariff		/* Calculate length of packet, then send that */
638170159Sariff
639170159Sariff		count += 14;		/* Ethernet header len */
640170159Sariff
641170159Sariff		mm = m;
642170159Sariff		for (mm = m; mm; mm = mm->m_next) {
643170159Sariff			count += mm->m_len;
644170159Sariff		}
645170159Sariff		if (clpoutbyte(count & 0xFF, LPMAXSPIN1, ppbus))
646170159Sariff			goto nend;
647170159Sariff		if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, ppbus))
648170159Sariff			goto nend;
649170159Sariff
650170159Sariff		/* Send dummy ethernet header */
651170159Sariff		for (i = 0; i < 12; i++) {
652170159Sariff			if (clpoutbyte(i, LPMAXSPIN1, ppbus))
653170159Sariff				goto nend;
654170159Sariff			chksum += i;
655170159Sariff		}
656170159Sariff
657170159Sariff		if (clpoutbyte(0x08, LPMAXSPIN1, ppbus))
658170159Sariff			goto nend;
659170159Sariff		if (clpoutbyte(0x00, LPMAXSPIN1, ppbus))
660170159Sariff			goto nend;
661170159Sariff		chksum += 0x08 + 0x00;		/* Add into checksum */
662170159Sariff
663170159Sariff		mm = m;
664170159Sariff		do {
665170159Sariff			cp = mtod(mm, u_char *);
666170159Sariff			len = mm->m_len;
667170159Sariff			while (len--) {
668170159Sariff				chksum += *cp;
669170159Sariff				if (clpoutbyte(*cp++, LPMAXSPIN2, ppbus))
670170159Sariff					goto nend;
671170159Sariff			}
672170159Sariff		} while ((mm = mm->m_next));
673170159Sariff
674170159Sariff		/* Send checksum */
675170159Sariff		if (clpoutbyte(chksum, LPMAXSPIN2, ppbus))
676170159Sariff			goto nend;
677170159Sariff
678170159Sariff		/* Go quiescent */
679170159Sariff		ppb_wdtr(ppbus, 0);
680170159Sariff
681170159Sariff		err = 0;			/* No errors */
682170159Sariff
683170159Sariff	nend:
684170159Sariff		if (err)  {			/* if we didn't timeout... */
685170159Sariff			ifp->if_oerrors++;
686170159Sariff			lprintf("X");
687170159Sariff		} else {
688170159Sariff			ifp->if_opackets++;
689170159Sariff			ifp->if_obytes += m->m_pkthdr.len;
690170159Sariff			if (bpf_peers_present(ifp->if_bpf))
691170159Sariff				lptap(ifp, m);
692170159Sariff		}
693170159Sariff
694170159Sariff		m_freem(m);
695170159Sariff
696170159Sariff		if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) {
697170159Sariff			lprintf("^");
698170159Sariff			lp_intr(dev);
699170159Sariff		}
700170159Sariff		(void) splx(s);
701170159Sariff		return (0);
702170159Sariff	}
703170159Sariff
704170159Sariff	if (ppb_rstr(ppbus) & LPIP_SHAKE) {
705170159Sariff		lprintf("&");
706170159Sariff		lp_intr(dev);
707170159Sariff	}
708170159Sariff
709170159Sariff	if (lpoutbyte(0x08, LPMAXSPIN1, ppbus))
710170159Sariff		goto end;
711170159Sariff	if (lpoutbyte(0x00, LPMAXSPIN2, ppbus))
712170159Sariff		goto end;
713170159Sariff
714170159Sariff	mm = m;
715170159Sariff	do {
716170159Sariff		cp = mtod(mm, u_char *);
717170159Sariff		len = mm->m_len;
718170159Sariff		while (len--)
719170159Sariff			if (lpoutbyte(*cp++, LPMAXSPIN2, ppbus))
720170159Sariff				goto end;
721170159Sariff	} while ((mm = mm->m_next));
722170159Sariff
723170159Sariff	err = 0;			/* no errors were encountered */
724170159Sariff
725170159Sariffend:
726170159Sariff	--cp;
727170159Sariff	ppb_wdtr(ppbus, txmitl[*cp] ^ 0x17);
728170159Sariff
729170159Sariff	if (err)  {			/* if we didn't timeout... */
730170159Sariff		ifp->if_oerrors++;
731170159Sariff		lprintf("X");
732170159Sariff	} else {
733170159Sariff		ifp->if_opackets++;
734170159Sariff		ifp->if_obytes += m->m_pkthdr.len;
735170159Sariff		if (bpf_peers_present(ifp->if_bpf))
736170159Sariff			lptap(ifp, m);
737170159Sariff	}
738170159Sariff
739170159Sariff	m_freem(m);
740170159Sariff
741170159Sariff	if (ppb_rstr(ppbus) & LPIP_SHAKE) {
742170159Sariff		lprintf("^");
743170159Sariff		lp_intr(dev);
744170159Sariff	}
745170159Sariff
746170159Sariff	(void) splx(s);
747170159Sariff	return (0);
748170159Sariff}
749170159Sariff
750170159Sariffstatic device_method_t lp_methods[] = {
751170159Sariff  	/* device interface */
752170159Sariff	DEVMETHOD(device_identify,	lp_identify),
753170159Sariff	DEVMETHOD(device_probe,		lp_probe),
754170159Sariff	DEVMETHOD(device_attach,	lp_attach),
755170159Sariff
756170159Sariff	{ 0, 0 }
757170159Sariff};
758170159Sariff
759170159Sariffstatic driver_t lp_driver = {
760170159Sariff	"plip",
761170159Sariff	lp_methods,
762170159Sariff	sizeof(struct lp_data),
763170159Sariff};
764170159Sariff
765170159SariffDRIVER_MODULE(plip, ppbus, lp_driver, lp_devclass, 0, 0);
766170159SariffMODULE_DEPEND(plip, ppbus, 1, 1, 1);
767170159Sariff