xref: /freebsd/sys/dev/ppbus/if_plip.c (revision 9162f64b58d01ec01481d60b6cdc06ffd8e8c7fc)
1 /*-
2  * Copyright (c) 1997 Poul-Henning Kamp
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  *	From Id: lpt.c,v 1.55.2.1 1996/11/12 09:08:38 phk Exp
27  */
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 /*
33  * Parallel port TCP/IP interfaces added.  I looked at the driver from
34  * MACH but this is a complete rewrite, and btw. incompatible, and it
35  * should perform better too.  I have never run the MACH driver though.
36  *
37  * This driver sends two bytes (0x08, 0x00) in front of each packet,
38  * to allow us to distinguish another format later.
39  *
40  * Now added a Linux/Crynwr compatibility mode which is enabled using
41  * IF_LINK0 - Tim Wilkinson.
42  *
43  * TODO:
44  *    Make HDLC/PPP mode, use IF_LLC1 to enable.
45  *
46  * Connect the two computers using a Laplink parallel cable to use this
47  * feature:
48  *
49  *      +----------------------------------------+
50  * 	|A-name	A-End	B-End	Descr.	Port/Bit |
51  *      +----------------------------------------+
52  *	|DATA0	2	15	Data	0/0x01   |
53  *	|-ERROR	15	2	   	1/0x08   |
54  *      +----------------------------------------+
55  *	|DATA1	3	13	Data	0/0x02	 |
56  *	|+SLCT	13	3	   	1/0x10   |
57  *      +----------------------------------------+
58  *	|DATA2	4	12	Data	0/0x04   |
59  *	|+PE	12	4	   	1/0x20   |
60  *      +----------------------------------------+
61  *	|DATA3	5	10	Strobe	0/0x08   |
62  *	|-ACK	10	5	   	1/0x40   |
63  *      +----------------------------------------+
64  *	|DATA4	6	11	Data	0/0x10   |
65  *	|BUSY	11	6	   	1/~0x80  |
66  *      +----------------------------------------+
67  *	|GND	18-25	18-25	GND	-        |
68  *      +----------------------------------------+
69  *
70  * Expect transfer-rates up to 75 kbyte/sec.
71  *
72  * If GCC could correctly grok
73  *	register int port asm("edx")
74  * the code would be cleaner
75  *
76  * Poul-Henning Kamp <phk@freebsd.org>
77  */
78 
79 /*
80  * Update for ppbus, PLIP support only - Nicolas Souchu
81  */
82 
83 #include "opt_plip.h"
84 
85 #include <sys/param.h>
86 #include <sys/systm.h>
87 #include <sys/module.h>
88 #include <sys/bus.h>
89 #include <sys/mbuf.h>
90 #include <sys/socket.h>
91 #include <sys/sockio.h>
92 #include <sys/kernel.h>
93 #include <sys/malloc.h>
94 
95 #include <machine/bus.h>
96 #include <machine/resource.h>
97 #include <sys/rman.h>
98 
99 #include <net/if.h>
100 #include <net/if_types.h>
101 #include <net/netisr.h>
102 
103 #include <netinet/in.h>
104 #include <netinet/in_var.h>
105 
106 #include <net/bpf.h>
107 
108 #include <dev/ppbus/ppbconf.h>
109 #include "ppbus_if.h"
110 #include <dev/ppbus/ppbio.h>
111 
112 #ifndef LPMTU			/* MTU for the lp# interfaces */
113 #define	LPMTU		1500
114 #endif
115 
116 #ifndef LPMAXSPIN1		/* DELAY factor for the lp# interfaces */
117 #define	LPMAXSPIN1	8000   /* Spinning for remote intr to happen */
118 #endif
119 
120 #ifndef LPMAXSPIN2		/* DELAY factor for the lp# interfaces */
121 #define	LPMAXSPIN2	500	/* Spinning for remote handshake to happen */
122 #endif
123 
124 #ifndef LPMAXERRS		/* Max errors before !RUNNING */
125 #define	LPMAXERRS	100
126 #endif
127 
128 #define	CLPIPHDRLEN	14	/* We send dummy ethernet addresses (two) + packet type in front of packet */
129 #define	CLPIP_SHAKE	0x80	/* This bit toggles between nibble reception */
130 #define	MLPIPHDRLEN	CLPIPHDRLEN
131 
132 #define	LPIPHDRLEN	2	/* We send 0x08, 0x00 in front of packet */
133 #define	LPIP_SHAKE	0x40	/* This bit toggles between nibble reception */
134 #if !defined(MLPIPHDRLEN) || LPIPHDRLEN > MLPIPHDRLEN
135 #define	MLPIPHDRLEN	LPIPHDRLEN
136 #endif
137 
138 #define	LPIPTBLSIZE	256	/* Size of octet translation table */
139 
140 #define	lprintf		if (lptflag) printf
141 
142 #ifdef PLIP_DEBUG
143 static int volatile lptflag = 1;
144 #else
145 static int volatile lptflag = 0;
146 #endif
147 
148 struct lp_data {
149 	struct  ifnet	*sc_ifp;
150 	device_t	sc_dev;
151 	u_char		*sc_ifbuf;
152 	int		sc_iferrs;
153 
154 	struct resource *res_irq;
155 };
156 
157 /* Tables for the lp# interface */
158 static u_char *txmith;
159 #define	txmitl (txmith + (1 * LPIPTBLSIZE))
160 #define	trecvh (txmith + (2 * LPIPTBLSIZE))
161 #define	trecvl (txmith + (3 * LPIPTBLSIZE))
162 
163 static u_char *ctxmith;
164 #define	ctxmitl (ctxmith + (1 * LPIPTBLSIZE))
165 #define	ctrecvh (ctxmith + (2 * LPIPTBLSIZE))
166 #define	ctrecvl (ctxmith + (3 * LPIPTBLSIZE))
167 
168 /* Functions for the lp# interface */
169 static int lpinittables(void);
170 static int lpioctl(struct ifnet *, u_long, caddr_t);
171 static int lpoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
172 	struct rtentry *);
173 static void lp_intr(void *);
174 
175 #define	DEVTOSOFTC(dev) \
176 	((struct lp_data *)device_get_softc(dev))
177 
178 static devclass_t lp_devclass;
179 
180 static void
181 lp_identify(driver_t *driver, device_t parent)
182 {
183 	device_t dev;
184 
185 	dev = device_find_child(parent, "plip", -1);
186 	if (!dev)
187 		BUS_ADD_CHILD(parent, 0, "plip", -1);
188 }
189 
190 static int
191 lp_probe(device_t dev)
192 {
193 
194 	device_set_desc(dev, "PLIP network interface");
195 
196 	return (0);
197 }
198 
199 static int
200 lp_attach(device_t dev)
201 {
202 	struct lp_data *lp = DEVTOSOFTC(dev);
203 	struct ifnet *ifp;
204 	int rid = 0;
205 
206 	lp->sc_dev = dev;
207 
208 	/*
209 	 * Reserve the interrupt resource.  If we don't have one, the
210 	 * attach fails.
211 	 */
212 	lp->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
213 	    RF_SHAREABLE);
214 	if (lp->res_irq == 0) {
215 		device_printf(dev, "cannot reserve interrupt, failed.\n");
216 		return (ENXIO);
217 	}
218 
219 	ifp = lp->sc_ifp = if_alloc(IFT_PARA);
220 	if (ifp == NULL) {
221 		return (ENOSPC);
222 	}
223 
224 	ifp->if_softc = lp;
225 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
226 	ifp->if_mtu = LPMTU;
227 	ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST |
228 	    IFF_NEEDSGIANT;
229 	ifp->if_ioctl = lpioctl;
230 	ifp->if_output = lpoutput;
231 	ifp->if_hdrlen = 0;
232 	ifp->if_addrlen = 0;
233 	ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
234 	if_attach(ifp);
235 
236 	bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
237 
238 	return (0);
239 }
240 /*
241  * Build the translation tables for the LPIP (BSD unix) protocol.
242  * We don't want to calculate these nasties in our tight loop, so we
243  * precalculate them when we initialize.
244  */
245 static int
246 lpinittables(void)
247 {
248 	int i;
249 
250 	if (txmith == NULL)
251 		txmith = malloc(4 * LPIPTBLSIZE, M_DEVBUF, M_NOWAIT);
252 
253 	if (txmith == NULL)
254 		return (1);
255 
256 	if (ctxmith == NULL)
257 		ctxmith = malloc(4 * LPIPTBLSIZE, M_DEVBUF, M_NOWAIT);
258 
259 	if (ctxmith == NULL)
260 		return (1);
261 
262 	for (i = 0; i < LPIPTBLSIZE; i++) {
263 		ctxmith[i] = (i & 0xF0) >> 4;
264 		ctxmitl[i] = 0x10 | (i & 0x0F);
265 		ctrecvh[i] = (i & 0x78) << 1;
266 		ctrecvl[i] = (i & 0x78) >> 3;
267 	}
268 
269 	for (i = 0; i < LPIPTBLSIZE; i++) {
270 		txmith[i] = ((i & 0x80) >> 3) | ((i & 0x70) >> 4) | 0x08;
271 		txmitl[i] = ((i & 0x08) << 1) | (i & 0x07);
272 		trecvh[i] = ((~i) & 0x80) | ((i & 0x38) << 1);
273 		trecvl[i] = (((~i) & 0x80) >> 4) | ((i & 0x38) >> 3);
274 	}
275 
276 	return (0);
277 }
278 
279 /*
280  * Process an ioctl request.
281  */
282 static int
283 lpioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
284 {
285 	struct lp_data *sc = ifp->if_softc;
286 	device_t dev = sc->sc_dev;
287 	device_t ppbus = device_get_parent(dev);
288 	struct ifaddr *ifa = (struct ifaddr *)data;
289 	struct ifreq *ifr = (struct ifreq *)data;
290 	u_char *ptr;
291 	void *ih;
292 	int error;
293 
294 	switch (cmd) {
295 	case SIOCSIFDSTADDR:
296 	case SIOCAIFADDR:
297 	case SIOCSIFADDR:
298 		if (ifa->ifa_addr->sa_family != AF_INET)
299 			return (EAFNOSUPPORT);
300 
301 		ifp->if_flags |= IFF_UP;
302 		/* FALLTHROUGH */
303 	case SIOCSIFFLAGS:
304 		if ((!(ifp->if_flags & IFF_UP)) &&
305 		    (ifp->if_drv_flags & IFF_DRV_RUNNING)) {
306 
307 			ppb_wctr(ppbus, 0x00);
308 			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
309 
310 			/* IFF_UP is not set, try to release the bus anyway */
311 			ppb_release_bus(ppbus, dev);
312 			break;
313 		}
314 		if (((ifp->if_flags & IFF_UP)) &&
315 		    (!(ifp->if_drv_flags & IFF_DRV_RUNNING))) {
316 
317 			/* XXX
318 			 * Should the request be interruptible?
319 			 */
320 			if ((error = ppb_request_bus(ppbus, dev, PPB_WAIT |
321 			    PPB_INTR)))
322 				return (error);
323 
324 			/* Now IFF_UP means that we own the bus */
325 			ppb_set_mode(ppbus, PPB_COMPATIBLE);
326 
327 			if (lpinittables()) {
328 				ppb_release_bus(ppbus, dev);
329 				return (ENOBUFS);
330 			}
331 
332 			sc->sc_ifbuf = malloc(sc->sc_ifp->if_mtu + MLPIPHDRLEN,
333 			    M_DEVBUF, M_WAITOK);
334 			if (sc->sc_ifbuf == NULL) {
335 				ppb_release_bus(ppbus, dev);
336 				return (ENOBUFS);
337 			}
338 
339 			/*
340 			 * Attach our interrupt handler.  It is
341 			 * detached later when the bus is released.
342 			 */
343 			if ((error = bus_setup_intr(dev, sc->res_irq,
344 			    INTR_TYPE_NET, NULL, lp_intr, dev, &ih))) {
345 				ppb_release_bus(ppbus, dev);
346 				return (error);
347 			}
348 
349 			ppb_wctr(ppbus, IRQENABLE);
350 			ifp->if_drv_flags |= IFF_DRV_RUNNING;
351 		}
352 		break;
353 
354 	case SIOCSIFMTU:
355 		ptr = sc->sc_ifbuf;
356 		sc->sc_ifbuf = malloc(ifr->ifr_mtu + MLPIPHDRLEN, M_DEVBUF,
357 		    M_NOWAIT);
358 		if (sc->sc_ifbuf == NULL) {
359 			sc->sc_ifbuf = ptr;
360 			return (ENOBUFS);
361 		}
362 		if (ptr)
363 			free(ptr, M_DEVBUF);
364 		sc->sc_ifp->if_mtu = ifr->ifr_mtu;
365 		break;
366 
367 	case SIOCGIFMTU:
368 		ifr->ifr_mtu = sc->sc_ifp->if_mtu;
369 		break;
370 
371 	case SIOCADDMULTI:
372 	case SIOCDELMULTI:
373 		if (ifr == 0) {
374 			return (EAFNOSUPPORT);		/* XXX */
375 		}
376 		switch (ifr->ifr_addr.sa_family) {
377 		case AF_INET:
378 			break;
379 		default:
380 			return (EAFNOSUPPORT);
381 		}
382 		break;
383 
384 	case SIOCGIFMEDIA:
385 		/*
386 		 * No ifmedia support at this stage; maybe use it
387 		 * in future for eg. protocol selection.
388 		 */
389 		return (EINVAL);
390 
391 	default:
392 		lprintf("LP:ioctl(0x%lx)\n", cmd);
393 		return (EINVAL);
394 	}
395 	return (0);
396 }
397 
398 static __inline int
399 clpoutbyte(u_char byte, int spin, device_t ppbus)
400 {
401 
402 	ppb_wdtr(ppbus, ctxmitl[byte]);
403 	while (ppb_rstr(ppbus) & CLPIP_SHAKE)
404 		if (--spin == 0) {
405 			return (1);
406 		}
407 	ppb_wdtr(ppbus, ctxmith[byte]);
408 	while (!(ppb_rstr(ppbus) & CLPIP_SHAKE))
409 		if (--spin == 0) {
410 			return (1);
411 		}
412 	return (0);
413 }
414 
415 static __inline int
416 clpinbyte(int spin, device_t ppbus)
417 {
418 	u_char c, cl;
419 
420 	while((ppb_rstr(ppbus) & CLPIP_SHAKE))
421 		if (!--spin) {
422 			return (-1);
423 		}
424 	cl = ppb_rstr(ppbus);
425 	ppb_wdtr(ppbus, 0x10);
426 
427 	while(!(ppb_rstr(ppbus) & CLPIP_SHAKE))
428 		if (!--spin) {
429 			return (-1);
430 		}
431 	c = ppb_rstr(ppbus);
432 	ppb_wdtr(ppbus, 0x00);
433 
434 	return (ctrecvl[cl] | ctrecvh[c]);
435 }
436 
437 static void
438 lptap(struct ifnet *ifp, struct mbuf *m)
439 {
440 	u_int32_t af = AF_INET;
441 
442 	bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m);
443 }
444 
445 static void
446 lp_intr(void *arg)
447 {
448 	device_t dev = (device_t)arg;
449 	device_t ppbus = device_get_parent(dev);
450 	struct lp_data *sc = DEVTOSOFTC(dev);
451 	int len, s, j;
452 	u_char *bp;
453 	u_char c, cl;
454 	struct mbuf *top;
455 
456 	s = splhigh();
457 
458 	if (sc->sc_ifp->if_flags & IFF_LINK0) {
459 
460 		/* Ack. the request */
461 		ppb_wdtr(ppbus, 0x01);
462 
463 		/* Get the packet length */
464 		j = clpinbyte(LPMAXSPIN2, ppbus);
465 		if (j == -1)
466 			goto err;
467 		len = j;
468 		j = clpinbyte(LPMAXSPIN2, ppbus);
469 		if (j == -1)
470 			goto err;
471 		len = len + (j << 8);
472 		if (len > sc->sc_ifp->if_mtu + MLPIPHDRLEN)
473 			goto err;
474 
475 		bp = sc->sc_ifbuf;
476 
477 		while (len--) {
478 			j = clpinbyte(LPMAXSPIN2, ppbus);
479 			if (j == -1) {
480 				goto err;
481 			}
482 			*bp++ = j;
483 		}
484 
485 		/* Get and ignore checksum */
486 		j = clpinbyte(LPMAXSPIN2, ppbus);
487 		if (j == -1) {
488 			goto err;
489 		}
490 
491 		len = bp - sc->sc_ifbuf;
492 		if (len <= CLPIPHDRLEN)
493 			goto err;
494 
495 		sc->sc_iferrs = 0;
496 
497 		len -= CLPIPHDRLEN;
498 		sc->sc_ifp->if_ipackets++;
499 		sc->sc_ifp->if_ibytes += len;
500 		top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, sc->sc_ifp,
501 		    0);
502 		if (top) {
503 			if (bpf_peers_present(sc->sc_ifp->if_bpf))
504 				lptap(sc->sc_ifp, top);
505 
506 			/* mbuf is free'd on failure. */
507 			netisr_queue(NETISR_IP, top);
508 		}
509 		goto done;
510 	}
511 	while ((ppb_rstr(ppbus) & LPIP_SHAKE)) {
512 		len = sc->sc_ifp->if_mtu + LPIPHDRLEN;
513 		bp  = sc->sc_ifbuf;
514 		while (len--) {
515 
516 			cl = ppb_rstr(ppbus);
517 			ppb_wdtr(ppbus, 8);
518 
519 			j = LPMAXSPIN2;
520 			while((ppb_rstr(ppbus) & LPIP_SHAKE))
521 				if (!--j)
522 					goto err;
523 
524 			c = ppb_rstr(ppbus);
525 			ppb_wdtr(ppbus, 0);
526 
527 			*bp++= trecvh[cl] | trecvl[c];
528 
529 			j = LPMAXSPIN2;
530 			while (!((cl = ppb_rstr(ppbus)) & LPIP_SHAKE)) {
531 				if (cl != c &&
532 				    (((cl = ppb_rstr(ppbus)) ^ 0xb8) & 0xf8) ==
533 				    (c & 0xf8))
534 					goto end;
535 				if (!--j)
536 					goto err;
537 			}
538 		}
539 
540 	end:
541 		len = bp - sc->sc_ifbuf;
542 		if (len <= LPIPHDRLEN)
543 			goto err;
544 
545 		sc->sc_iferrs = 0;
546 
547 		len -= LPIPHDRLEN;
548 		sc->sc_ifp->if_ipackets++;
549 		sc->sc_ifp->if_ibytes += len;
550 		top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, sc->sc_ifp,
551 		    0);
552 		if (top) {
553 			if (bpf_peers_present(sc->sc_ifp->if_bpf))
554 				lptap(sc->sc_ifp, top);
555 
556 			/* mbuf is free'd on failure. */
557 			netisr_queue(NETISR_IP, top);
558 		}
559 	}
560 	goto done;
561 
562 err:
563 	ppb_wdtr(ppbus, 0);
564 	lprintf("R");
565 	sc->sc_ifp->if_ierrors++;
566 	sc->sc_iferrs++;
567 
568 	/*
569 	 * We are not able to send receive anything for now,
570 	 * so stop wasting our time
571 	 */
572 	if (sc->sc_iferrs > LPMAXERRS) {
573 		if_printf(sc->sc_ifp, "Too many errors, Going off-line.\n");
574 		ppb_wctr(ppbus, 0x00);
575 		sc->sc_ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
576 		sc->sc_iferrs = 0;
577 	}
578 
579 done:
580 	splx(s);
581 }
582 
583 static __inline int
584 lpoutbyte(u_char byte, int spin, device_t ppbus)
585 {
586 
587 	ppb_wdtr(ppbus, txmith[byte]);
588 	while (!(ppb_rstr(ppbus) & LPIP_SHAKE))
589 		if (--spin == 0)
590 			return (1);
591 	ppb_wdtr(ppbus, txmitl[byte]);
592 	while (ppb_rstr(ppbus) & LPIP_SHAKE)
593 		if (--spin == 0)
594 			return (1);
595 	return (0);
596 }
597 
598 static int
599 lpoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
600     struct rtentry *rt)
601 {
602 	struct lp_data *sc = ifp->if_softc;
603 	device_t dev = sc->sc_dev;
604 	device_t ppbus = device_get_parent(dev);
605 	int s, err;
606 	struct mbuf *mm;
607 	u_char *cp = "\0\0";
608 	u_char chksum = 0;
609 	int count = 0;
610 	int i, len, spin;
611 
612 	/* We need a sensible value if we abort */
613 	cp++;
614 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
615 
616 	err = 1;		/* assume we're aborting because of an error */
617 
618 	s = splhigh();
619 
620 	/* Suspend (on laptops) or receive-errors might have taken us offline */
621 	ppb_wctr(ppbus, IRQENABLE);
622 
623 	if (ifp->if_flags & IFF_LINK0) {
624 		if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) {
625 			lprintf("&");
626 			lp_intr(dev);
627 		}
628 
629 		/* Alert other end to pending packet */
630 		spin = LPMAXSPIN1;
631 		ppb_wdtr(ppbus, 0x08);
632 		while ((ppb_rstr(ppbus) & 0x08) == 0)
633 			if (--spin == 0) {
634 				goto nend;
635 			}
636 
637 		/* Calculate length of packet, then send that */
638 
639 		count += 14;		/* Ethernet header len */
640 
641 		mm = m;
642 		for (mm = m; mm; mm = mm->m_next) {
643 			count += mm->m_len;
644 		}
645 		if (clpoutbyte(count & 0xFF, LPMAXSPIN1, ppbus))
646 			goto nend;
647 		if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, ppbus))
648 			goto nend;
649 
650 		/* Send dummy ethernet header */
651 		for (i = 0; i < 12; i++) {
652 			if (clpoutbyte(i, LPMAXSPIN1, ppbus))
653 				goto nend;
654 			chksum += i;
655 		}
656 
657 		if (clpoutbyte(0x08, LPMAXSPIN1, ppbus))
658 			goto nend;
659 		if (clpoutbyte(0x00, LPMAXSPIN1, ppbus))
660 			goto nend;
661 		chksum += 0x08 + 0x00;		/* Add into checksum */
662 
663 		mm = m;
664 		do {
665 			cp = mtod(mm, u_char *);
666 			len = mm->m_len;
667 			while (len--) {
668 				chksum += *cp;
669 				if (clpoutbyte(*cp++, LPMAXSPIN2, ppbus))
670 					goto nend;
671 			}
672 		} while ((mm = mm->m_next));
673 
674 		/* Send checksum */
675 		if (clpoutbyte(chksum, LPMAXSPIN2, ppbus))
676 			goto nend;
677 
678 		/* Go quiescent */
679 		ppb_wdtr(ppbus, 0);
680 
681 		err = 0;			/* No errors */
682 
683 	nend:
684 		if (err)  {			/* if we didn't timeout... */
685 			ifp->if_oerrors++;
686 			lprintf("X");
687 		} else {
688 			ifp->if_opackets++;
689 			ifp->if_obytes += m->m_pkthdr.len;
690 			if (bpf_peers_present(ifp->if_bpf))
691 				lptap(ifp, m);
692 		}
693 
694 		m_freem(m);
695 
696 		if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) {
697 			lprintf("^");
698 			lp_intr(dev);
699 		}
700 		(void) splx(s);
701 		return (0);
702 	}
703 
704 	if (ppb_rstr(ppbus) & LPIP_SHAKE) {
705 		lprintf("&");
706 		lp_intr(dev);
707 	}
708 
709 	if (lpoutbyte(0x08, LPMAXSPIN1, ppbus))
710 		goto end;
711 	if (lpoutbyte(0x00, LPMAXSPIN2, ppbus))
712 		goto end;
713 
714 	mm = m;
715 	do {
716 		cp = mtod(mm, u_char *);
717 		len = mm->m_len;
718 		while (len--)
719 			if (lpoutbyte(*cp++, LPMAXSPIN2, ppbus))
720 				goto end;
721 	} while ((mm = mm->m_next));
722 
723 	err = 0;			/* no errors were encountered */
724 
725 end:
726 	--cp;
727 	ppb_wdtr(ppbus, txmitl[*cp] ^ 0x17);
728 
729 	if (err)  {			/* if we didn't timeout... */
730 		ifp->if_oerrors++;
731 		lprintf("X");
732 	} else {
733 		ifp->if_opackets++;
734 		ifp->if_obytes += m->m_pkthdr.len;
735 		if (bpf_peers_present(ifp->if_bpf))
736 			lptap(ifp, m);
737 	}
738 
739 	m_freem(m);
740 
741 	if (ppb_rstr(ppbus) & LPIP_SHAKE) {
742 		lprintf("^");
743 		lp_intr(dev);
744 	}
745 
746 	(void) splx(s);
747 	return (0);
748 }
749 
750 static device_method_t lp_methods[] = {
751   	/* device interface */
752 	DEVMETHOD(device_identify,	lp_identify),
753 	DEVMETHOD(device_probe,		lp_probe),
754 	DEVMETHOD(device_attach,	lp_attach),
755 
756 	{ 0, 0 }
757 };
758 
759 static driver_t lp_driver = {
760 	"plip",
761 	lp_methods,
762 	sizeof(struct lp_data),
763 };
764 
765 DRIVER_MODULE(plip, ppbus, lp_driver, lp_devclass, 0, 0);
766 MODULE_DEPEND(plip, ppbus, 1, 1, 1);
767