xref: /freebsd/sys/dev/ppbus/if_plip.c (revision 11afcc8f9f96d657b8e6f7547c02c1957331fc96)
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  *	$Id$
28  */
29 
30 /*
31  * Parallel port TCP/IP interfaces added.  I looked at the driver from
32  * MACH but this is a complete rewrite, and btw. incompatible, and it
33  * should perform better too.  I have never run the MACH driver though.
34  *
35  * This driver sends two bytes (0x08, 0x00) in front of each packet,
36  * to allow us to distinguish another format later.
37  *
38  * Now added an Linux/Crynwr compatibility mode which is enabled using
39  * IF_LINK0 - Tim Wilkinson.
40  *
41  * TODO:
42  *    Make HDLC/PPP mode, use IF_LLC1 to enable.
43  *
44  * Connect the two computers using a Laplink parallel cable to use this
45  * feature:
46  *
47  *      +----------------------------------------+
48  * 	|A-name	A-End	B-End	Descr.	Port/Bit |
49  *      +----------------------------------------+
50  *	|DATA0	2	15	Data	0/0x01   |
51  *	|-ERROR	15	2	   	1/0x08   |
52  *      +----------------------------------------+
53  *	|DATA1	3	13	Data	0/0x02	 |
54  *	|+SLCT	13	3	   	1/0x10   |
55  *      +----------------------------------------+
56  *	|DATA2	4	12	Data	0/0x04   |
57  *	|+PE	12	4	   	1/0x20   |
58  *      +----------------------------------------+
59  *	|DATA3	5	10	Strobe	0/0x08   |
60  *	|-ACK	10	5	   	1/0x40   |
61  *      +----------------------------------------+
62  *	|DATA4	6	11	Data	0/0x10   |
63  *	|BUSY	11	6	   	1/~0x80  |
64  *      +----------------------------------------+
65  *	|GND	18-25	18-25	GND	-        |
66  *      +----------------------------------------+
67  *
68  * Expect transfer-rates up to 75 kbyte/sec.
69  *
70  * If GCC could correctly grok
71  *	register int port asm("edx")
72  * the code would be cleaner
73  *
74  * Poul-Henning Kamp <phk@freebsd.org>
75  */
76 
77 /*
78  * Update for ppbus, PLIP support only - Nicolas Souchu
79  */
80 
81 #ifdef KERNEL
82 #include <sys/param.h>
83 #include <sys/systm.h>
84 #include <sys/proc.h>
85 #include <sys/mbuf.h>
86 #include <sys/socket.h>
87 #include <sys/filio.h>
88 #include <sys/sockio.h>
89 #include <sys/kernel.h>
90 #include <sys/time.h>
91 #include <sys/malloc.h>
92 
93 #include <net/if.h>
94 #include <net/if_types.h>
95 #include <net/netisr.h>
96 
97 #endif /* KERNEL */
98 #include <sys/mbuf.h>
99 #include <sys/socket.h>
100 #include <net/netisr.h>
101 #include <net/route.h>
102 #include <netinet/in.h>
103 #include <netinet/in_systm.h>
104 #include <netinet/in_var.h>
105 #include <netinet/ip.h>
106 #include <netinet/if_ether.h>
107 
108 #include "bpfilter.h"
109 #if NBPFILTER > 0
110 #include <net/bpf.h>
111 #include <net/bpfdesc.h>
112 #endif
113 
114 #include <dev/ppbus/ppbconf.h>
115 #include <dev/ppbus/nlpt.h>
116 
117 #ifndef LPMTU			/* MTU for the lp# interfaces */
118 #define	LPMTU	1500
119 #endif
120 
121 #ifndef LPMAXSPIN1		/* DELAY factor for the lp# interfaces */
122 #define	LPMAXSPIN1	8000   /* Spinning for remote intr to happen */
123 #endif
124 
125 #ifndef LPMAXSPIN2		/* DELAY factor for the lp# interfaces */
126 #define	LPMAXSPIN2	500	/* Spinning for remote handshake to happen */
127 #endif
128 
129 #ifndef LPMAXERRS		/* Max errors before !RUNNING */
130 #define	LPMAXERRS	100
131 #endif
132 
133 #define CLPIPHDRLEN	14	/* We send dummy ethernet addresses (two) + packet type in front of packet */
134 #define	CLPIP_SHAKE	0x80	/* This bit toggles between nibble reception */
135 #define MLPIPHDRLEN	CLPIPHDRLEN
136 
137 #define LPIPHDRLEN	2	/* We send 0x08, 0x00 in front of packet */
138 #define	LPIP_SHAKE	0x40	/* This bit toggles between nibble reception */
139 #if !defined(MLPIPHDRLEN) || LPIPHDRLEN > MLPIPHDRLEN
140 #define MLPIPHDRLEN	LPIPHDRLEN
141 #endif
142 
143 #define	LPIPTBLSIZE	256	/* Size of octet translation table */
144 
145 #define DEBUG
146 
147 #ifndef DEBUG
148 #define lprintf (void)
149 #else
150 #define lprintf		if (lptflag) printf
151 static int volatile lptflag = 1;
152 #endif
153 
154 struct lpt_softc {
155 	unsigned short lp_unit;
156 
157 	struct ppb_device lp_dev;
158 
159 	struct  ifnet	sc_if;
160 	u_char		*sc_ifbuf;
161 	int		sc_iferrs;
162 };
163 
164 static int	nlp = 0;
165 #define MAXPLIP	8			/* XXX not much better! */
166 static struct lpt_softc *lpdata[MAXPLIP];
167 
168 
169 /* Tables for the lp# interface */
170 static u_char *txmith;
171 #define txmitl (txmith+(1*LPIPTBLSIZE))
172 #define trecvh (txmith+(2*LPIPTBLSIZE))
173 #define trecvl (txmith+(3*LPIPTBLSIZE))
174 
175 static u_char *ctxmith;
176 #define ctxmitl (ctxmith+(1*LPIPTBLSIZE))
177 #define ctrecvh (ctxmith+(2*LPIPTBLSIZE))
178 #define ctrecvl (ctxmith+(3*LPIPTBLSIZE))
179 
180 /* Functions for the lp# interface */
181 static struct ppb_device	*lpprobe(struct ppb_data *);
182 static int			lpattach(struct ppb_device *);
183 
184 static int lpinittables(void);
185 static int lpioctl(struct ifnet *, u_long, caddr_t);
186 static int lpoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
187 	struct rtentry *);
188 static void lpintr(int);
189 
190 /*
191  * Make ourselves visible as a ppbus driver
192  */
193 
194 static struct ppb_driver lpdriver = {
195     lpprobe, lpattach, "lp"
196 };
197 DATA_SET(ppbdriver_set, lpdriver);
198 
199 
200 /*
201  * lpprobe()
202  */
203 static struct ppb_device *
204 lpprobe(struct ppb_data *ppb)
205 {
206 	struct lpt_softc *lp;
207 
208 	/* if we haven't interrupts, the probe fails */
209 	if (!ppb->ppb_link->id_irq)
210 		return (0);
211 
212 	lp = (struct lpt_softc *) malloc(sizeof(struct lpt_softc),
213 							M_TEMP, M_NOWAIT);
214 	if (!lp) {
215 		printf("lp: cannot malloc!\n");
216 		return (0);
217 	}
218 	bzero(lp, sizeof(struct lpt_softc));
219 
220 	lpdata[nlp] = lp;
221 
222 	/*
223 	 * lp dependent initialisation.
224 	 */
225 	lp->lp_unit = nlp;
226 
227 	if (bootverbose)
228 		printf("plip: irq %d", ppb->ppb_link->id_irq);
229 
230 	/*
231 	 * ppbus dependent initialisation.
232 	 */
233 	lp->lp_dev.id_unit = lp->lp_unit;
234 	lp->lp_dev.name = lpdriver.name;
235 	lp->lp_dev.ppb = ppb;
236 	lp->lp_dev.intr = lpintr;
237 
238 	/* Ok, go to next device on next probe */
239 	nlp ++;
240 
241 	return (&lp->lp_dev);
242 }
243 
244 static int
245 lpattach (struct ppb_device *dev)
246 {
247 	int unit = dev->id_unit;
248 	struct lpt_softc *sc = lpdata[unit];
249 	struct ifnet *ifp = &sc->sc_if;
250 
251 	/*
252 	 * Report ourselves
253 	 */
254 	printf("plip%d: <PLIP network interface> on ppbus %d\n",
255 	       dev->id_unit, dev->ppb->ppb_link->adapter_unit);
256 
257 	ifp->if_softc = sc;
258 	ifp->if_name = "lp";
259 	ifp->if_unit = unit;
260 	ifp->if_mtu = LPMTU;
261 	ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST;
262 	ifp->if_ioctl = lpioctl;
263 	ifp->if_output = lpoutput;
264 	ifp->if_type = IFT_PARA;
265 	ifp->if_hdrlen = 0;
266 	ifp->if_addrlen = 0;
267 	ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
268 	if_attach(ifp);
269 
270 #if NBPFILTER > 0
271 	bpfattach(ifp, DLT_NULL, LPIPHDRLEN);
272 #endif
273 
274 	return (1);
275 }
276 /*
277  * Build the translation tables for the LPIP (BSD unix) protocol.
278  * We don't want to calculate these nasties in our tight loop, so we
279  * precalculate them when we initialize.
280  */
281 static int
282 lpinittables (void)
283 {
284     int i;
285 
286     if (!txmith)
287 	txmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT);
288 
289     if (!txmith)
290 	return 1;
291 
292     if (!ctxmith)
293 	ctxmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT);
294 
295     if (!ctxmith)
296 	return 1;
297 
298     for (i=0; i < LPIPTBLSIZE; i++) {
299 	ctxmith[i] = (i & 0xF0) >> 4;
300 	ctxmitl[i] = 0x10 | (i & 0x0F);
301 	ctrecvh[i] = (i & 0x78) << 1;
302 	ctrecvl[i] = (i & 0x78) >> 3;
303     }
304 
305     for (i=0; i < LPIPTBLSIZE; i++) {
306 	txmith[i] = ((i & 0x80) >> 3) | ((i & 0x70) >> 4) | 0x08;
307 	txmitl[i] = ((i & 0x08) << 1) | (i & 0x07);
308 	trecvh[i] = ((~i) & 0x80) | ((i & 0x38) << 1);
309 	trecvl[i] = (((~i) & 0x80) >> 4) | ((i & 0x38) >> 3);
310     }
311 
312     return 0;
313 }
314 
315 /*
316  * Process an ioctl request.
317  */
318 
319 static int
320 lpioctl (struct ifnet *ifp, u_long cmd, caddr_t data)
321 {
322     struct lpt_softc *sc = lpdata[ifp->if_unit];
323     struct ifaddr *ifa = (struct ifaddr *)data;
324     struct ifreq *ifr = (struct ifreq *)data;
325     u_char *ptr;
326     int error;
327 
328     switch (cmd) {
329 
330     case SIOCSIFDSTADDR:
331     case SIOCAIFADDR:
332     case SIOCSIFADDR:
333 	if (ifa->ifa_addr->sa_family != AF_INET)
334 	    return EAFNOSUPPORT;
335 
336 	ifp->if_flags |= IFF_UP;
337 	/* FALLTHROUGH */
338     case SIOCSIFFLAGS:
339 	if ((!(ifp->if_flags & IFF_UP)) && (ifp->if_flags & IFF_RUNNING)) {
340 
341 	    ppb_wctr(&sc->lp_dev, 0x00);
342 	    ifp->if_flags &= ~IFF_RUNNING;
343 
344 	    /* IFF_UP is not set, try to release the bus anyway */
345 	    ppb_release_bus(&sc->lp_dev);
346 	    break;
347 	}
348 	if (((ifp->if_flags & IFF_UP)) && (!(ifp->if_flags & IFF_RUNNING))) {
349 
350 	    /*
351 	     * Try to allocate the ppbus as soon as possible
352 	     * With ppbus allocation, interrupts are enabled
353 	     * Now IFF_UP means that we own the bus
354 	     *
355 	     * XXX
356 	     * Should the request be interruptible?
357 	     */
358 	    if ((error = ppb_request_bus(&sc->lp_dev, PPB_WAIT|PPB_INTR)))
359 		return (error);
360 
361 	    if (lpinittables()) {
362 		ppb_release_bus(&sc->lp_dev);
363 		return ENOBUFS;
364 	    }
365 
366 	    sc->sc_ifbuf = malloc(sc->sc_if.if_mtu + MLPIPHDRLEN,
367 				  M_DEVBUF, M_WAITOK);
368 	    if (!sc->sc_ifbuf) {
369 		ppb_release_bus(&sc->lp_dev);
370 		return ENOBUFS;
371 	    }
372 
373 	    ppb_wctr(&sc->lp_dev, LPC_ENA);
374 	    ifp->if_flags |= IFF_RUNNING;
375 	}
376 	break;
377 
378     case SIOCSIFMTU:
379 	ptr = sc->sc_ifbuf;
380 	sc->sc_ifbuf = malloc(ifr->ifr_mtu+MLPIPHDRLEN, M_DEVBUF, M_NOWAIT);
381 	if (!sc->sc_ifbuf) {
382 	    sc->sc_ifbuf = ptr;
383 	    return ENOBUFS;
384 	}
385 	if (ptr)
386 	    free(ptr,M_DEVBUF);
387 	sc->sc_if.if_mtu = ifr->ifr_mtu;
388 	break;
389 
390     case SIOCGIFMTU:
391 	ifr->ifr_mtu = sc->sc_if.if_mtu;
392 	break;
393 
394     case SIOCADDMULTI:
395     case SIOCDELMULTI:
396 	if (ifr == 0) {
397 	    return EAFNOSUPPORT;		/* XXX */
398 	}
399 	switch (ifr->ifr_addr.sa_family) {
400 
401 	case AF_INET:
402 	    break;
403 
404 	default:
405 	    return EAFNOSUPPORT;
406 	}
407 	break;
408 
409     default:
410 	lprintf("LP:ioctl(0x%x)\n",cmd);
411 	return EINVAL;
412     }
413     return 0;
414 }
415 
416 static __inline int
417 clpoutbyte (u_char byte, int spin, struct ppb_device *dev)
418 {
419 	ppb_wdtr(dev, ctxmitl[byte]);
420 	while (ppb_rstr(dev) & CLPIP_SHAKE)
421 		if (--spin == 0) {
422 			return 1;
423 		}
424 	ppb_wdtr(dev, ctxmith[byte]);
425 	while (!(ppb_rstr(dev) & CLPIP_SHAKE))
426 		if (--spin == 0) {
427 			return 1;
428 		}
429 	return 0;
430 }
431 
432 static __inline int
433 clpinbyte (int spin, struct ppb_device *dev)
434 {
435 	int c, cl;
436 
437 	while((ppb_rstr(dev) & CLPIP_SHAKE))
438 	    if(!--spin) {
439 		return -1;
440 	    }
441 	cl = ppb_rstr(dev);
442 	ppb_wdtr(dev, 0x10);
443 
444 	while(!(ppb_rstr(dev) & CLPIP_SHAKE))
445 	    if(!--spin) {
446 		return -1;
447 	    }
448 	c = ppb_rstr(dev);
449 	ppb_wdtr(dev, 0x00);
450 
451 	return (ctrecvl[cl] | ctrecvh[c]);
452 }
453 
454 static void
455 lpintr (int unit)
456 {
457 	struct   lpt_softc *sc = lpdata[unit];
458 	int len, s, j;
459 	u_char *bp;
460 	u_char c, cl;
461 	struct mbuf *top;
462 
463 	s = splhigh();
464 
465 	if (sc->sc_if.if_flags & IFF_LINK0) {
466 
467 	    /* Ack. the request */
468 	    ppb_wdtr(&sc->lp_dev, 0x01);
469 
470 	    /* Get the packet length */
471 	    j = clpinbyte(LPMAXSPIN2, &sc->lp_dev);
472 	    if (j == -1)
473 		goto err;
474 	    len = j;
475 	    j = clpinbyte(LPMAXSPIN2, &sc->lp_dev);
476 	    if (j == -1)
477 		goto err;
478 	    len = len + (j << 8);
479 	    if (len > sc->sc_if.if_mtu + MLPIPHDRLEN)
480 		goto err;
481 
482 	    bp  = sc->sc_ifbuf;
483 
484 	    while (len--) {
485 	        j = clpinbyte(LPMAXSPIN2, &sc->lp_dev);
486 	        if (j == -1) {
487 		    goto err;
488 	        }
489 	        *bp++ = j;
490 	    }
491 	    /* Get and ignore checksum */
492 	    j = clpinbyte(LPMAXSPIN2, &sc->lp_dev);
493 	    if (j == -1) {
494 	        goto err;
495 	    }
496 
497 	    len = bp - sc->sc_ifbuf;
498 	    if (len <= CLPIPHDRLEN)
499 	        goto err;
500 
501 	    sc->sc_iferrs = 0;
502 
503 	    if (IF_QFULL(&ipintrq)) {
504 	        lprintf("DROP");
505 	        IF_DROP(&ipintrq);
506 		goto done;
507 	    }
508 	    len -= CLPIPHDRLEN;
509 	    sc->sc_if.if_ipackets++;
510 	    sc->sc_if.if_ibytes += len;
511 	    top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, &sc->sc_if, 0);
512 	    if (top) {
513 	        IF_ENQUEUE(&ipintrq, top);
514 	        schednetisr(NETISR_IP);
515 	    }
516 	    goto done;
517 	}
518 	while ((ppb_rstr(&sc->lp_dev) & LPIP_SHAKE)) {
519 	    len = sc->sc_if.if_mtu + LPIPHDRLEN;
520 	    bp  = sc->sc_ifbuf;
521 	    while (len--) {
522 
523 		cl = ppb_rstr(&sc->lp_dev);
524 		ppb_wdtr(&sc->lp_dev, 8);
525 
526 		j = LPMAXSPIN2;
527 		while((ppb_rstr(&sc->lp_dev) & LPIP_SHAKE))
528 		    if(!--j) goto err;
529 
530 		c = ppb_rstr(&sc->lp_dev);
531 		ppb_wdtr(&sc->lp_dev, 0);
532 
533 		*bp++= trecvh[cl] | trecvl[c];
534 
535 		j = LPMAXSPIN2;
536 		while (!((cl=ppb_rstr(&sc->lp_dev)) & LPIP_SHAKE)) {
537 		    if (cl != c &&
538 			(((cl = ppb_rstr(&sc->lp_dev)) ^ 0xb8) & 0xf8) ==
539 			  (c & 0xf8))
540 			goto end;
541 		    if (!--j) goto err;
542 		}
543 	    }
544 
545 	end:
546 	    len = bp - sc->sc_ifbuf;
547 	    if (len <= LPIPHDRLEN)
548 		goto err;
549 
550 	    sc->sc_iferrs = 0;
551 
552 	    if (IF_QFULL(&ipintrq)) {
553 		lprintf("DROP");
554 		IF_DROP(&ipintrq);
555 		goto done;
556 	    }
557 #if NBPFILTER > 0
558 	    if (sc->sc_if.if_bpf) {
559 		bpf_tap(&sc->sc_if, sc->sc_ifbuf, len);
560 	    }
561 #endif
562 	    len -= LPIPHDRLEN;
563 	    sc->sc_if.if_ipackets++;
564 	    sc->sc_if.if_ibytes += len;
565 	    top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, &sc->sc_if, 0);
566 	    if (top) {
567 		    IF_ENQUEUE(&ipintrq, top);
568 		    schednetisr(NETISR_IP);
569 	    }
570 	}
571 	goto done;
572 
573     err:
574 	ppb_wdtr(&sc->lp_dev, 0);
575 	lprintf("R");
576 	sc->sc_if.if_ierrors++;
577 	sc->sc_iferrs++;
578 
579 	/*
580 	 * We are not able to send receive anything for now,
581 	 * so stop wasting our time
582 	 */
583 	if (sc->sc_iferrs > LPMAXERRS) {
584 	    printf("lp%d: Too many errors, Going off-line.\n", unit);
585 	    ppb_wctr(&sc->lp_dev, 0x00);
586 	    sc->sc_if.if_flags &= ~IFF_RUNNING;
587 	    sc->sc_iferrs=0;
588 	}
589 
590     done:
591 	splx(s);
592 	return;
593 }
594 
595 static __inline int
596 lpoutbyte (u_char byte, int spin, struct ppb_device *dev)
597 {
598     ppb_wdtr(dev, txmith[byte]);
599     while (!(ppb_rstr(dev) & LPIP_SHAKE))
600 	if (--spin == 0)
601 		return 1;
602     ppb_wdtr(dev, txmitl[byte]);
603     while (ppb_rstr(dev) & LPIP_SHAKE)
604 	if (--spin == 0)
605 		return 1;
606     return 0;
607 }
608 
609 static int
610 lpoutput (struct ifnet *ifp, struct mbuf *m,
611 	  struct sockaddr *dst, struct rtentry *rt)
612 {
613     struct lpt_softc *sc = lpdata[ifp->if_unit];
614     int s, err;
615     struct mbuf *mm;
616     u_char *cp = "\0\0";
617     u_char chksum = 0;
618     int count = 0;
619     int i;
620     int spin;
621 
622     /* We need a sensible value if we abort */
623     cp++;
624     ifp->if_flags |= IFF_RUNNING;
625 
626     err = 1;			/* assume we're aborting because of an error */
627 
628     s = splhigh();
629 
630     /* Suspend (on laptops) or receive-errors might have taken us offline */
631     ppb_wctr(&sc->lp_dev, LPC_ENA);
632 
633     if (ifp->if_flags & IFF_LINK0) {
634 
635 	if (!(ppb_rstr(&sc->lp_dev) & CLPIP_SHAKE)) {
636 	    lprintf("&");
637 	    lpintr(ifp->if_unit);
638 	}
639 
640 	/* Alert other end to pending packet */
641 	spin = LPMAXSPIN1;
642 	ppb_wdtr(&sc->lp_dev, 0x08);
643 	while ((ppb_rstr(&sc->lp_dev) & 0x08) == 0)
644 		if (--spin == 0) {
645 			goto nend;
646 		}
647 
648 	/* Calculate length of packet, then send that */
649 
650 	count += 14;		/* Ethernet header len */
651 
652 	mm = m;
653 	for (mm = m; mm; mm = mm->m_next) {
654 		count += mm->m_len;
655 	}
656 	if (clpoutbyte(count & 0xFF, LPMAXSPIN1, &sc->lp_dev))
657 		goto nend;
658 	if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, &sc->lp_dev))
659 		goto nend;
660 
661 	/* Send dummy ethernet header */
662 	for (i = 0; i < 12; i++) {
663 		if (clpoutbyte(i, LPMAXSPIN1, &sc->lp_dev))
664 			goto nend;
665 		chksum += i;
666 	}
667 
668 	if (clpoutbyte(0x08, LPMAXSPIN1, &sc->lp_dev))
669 		goto nend;
670 	if (clpoutbyte(0x00, LPMAXSPIN1, &sc->lp_dev))
671 		goto nend;
672 	chksum += 0x08 + 0x00;		/* Add into checksum */
673 
674 	mm = m;
675 	do {
676 		cp = mtod(mm, u_char *);
677 		while (mm->m_len--) {
678 			chksum += *cp;
679 			if (clpoutbyte(*cp++, LPMAXSPIN2, &sc->lp_dev))
680 				goto nend;
681 		}
682 	} while ((mm = mm->m_next));
683 
684 	/* Send checksum */
685 	if (clpoutbyte(chksum, LPMAXSPIN2, &sc->lp_dev))
686 		goto nend;
687 
688 	/* Go quiescent */
689 	ppb_wdtr(&sc->lp_dev, 0);
690 
691 	err = 0;			/* No errors */
692 
693 	nend:
694 	if (err)  {				/* if we didn't timeout... */
695 		ifp->if_oerrors++;
696 		lprintf("X");
697 	} else {
698 		ifp->if_opackets++;
699 		ifp->if_obytes += m->m_pkthdr.len;
700 	}
701 
702 	m_freem(m);
703 
704 	if (!(ppb_rstr(&sc->lp_dev) & CLPIP_SHAKE)) {
705 		lprintf("^");
706 		lpintr(ifp->if_unit);
707 	}
708 	(void) splx(s);
709 	return 0;
710     }
711 
712     if (ppb_rstr(&sc->lp_dev) & LPIP_SHAKE) {
713         lprintf("&");
714         lpintr(ifp->if_unit);
715     }
716 
717     if (lpoutbyte(0x08, LPMAXSPIN1, &sc->lp_dev))
718         goto end;
719     if (lpoutbyte(0x00, LPMAXSPIN2, &sc->lp_dev))
720         goto end;
721 
722     mm = m;
723     do {
724         cp = mtod(mm,u_char *);
725         while (mm->m_len--)
726 	    if (lpoutbyte(*cp++, LPMAXSPIN2, &sc->lp_dev))
727 	        goto end;
728     } while ((mm = mm->m_next));
729 
730     err = 0;				/* no errors were encountered */
731 
732     end:
733     --cp;
734     ppb_wdtr(&sc->lp_dev, txmitl[*cp] ^ 0x17);
735 
736     if (err)  {				/* if we didn't timeout... */
737 	ifp->if_oerrors++;
738         lprintf("X");
739     } else {
740 	ifp->if_opackets++;
741 	ifp->if_obytes += m->m_pkthdr.len;
742 #if NBPFILTER > 0
743 	if (ifp->if_bpf) {
744 	    /*
745 	     * We need to prepend the packet type as
746 	     * a two byte field.  Cons up a dummy header
747 	     * to pacify bpf.  This is safe because bpf
748 	     * will only read from the mbuf (i.e., it won't
749 	     * try to free it or keep a pointer to it).
750 	     */
751 	    struct mbuf m0;
752 	    u_short hdr = 0x800;
753 
754 	    m0.m_next = m;
755 	    m0.m_len = 2;
756 	    m0.m_data = (char *)&hdr;
757 
758 	    bpf_mtap(ifp, &m0);
759 	}
760 #endif
761     }
762 
763     m_freem(m);
764 
765     if (ppb_rstr(&sc->lp_dev) & LPIP_SHAKE) {
766 	lprintf("^");
767 	lpintr(ifp->if_unit);
768     }
769 
770     (void) splx(s);
771     return 0;
772 }
773