if_plip.c revision 55939
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 * $FreeBSD: head/sys/dev/ppbus/if_plip.c 55939 2000-01-14 00:18:06Z nsouch $
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#include "plip.h"
81
82#if NPLIP > 0
83
84#include "opt_plip.h"
85
86#include <sys/param.h>
87#include <sys/systm.h>
88#include <sys/module.h>
89#include <sys/bus.h>
90#include <sys/conf.h>
91#include <sys/mbuf.h>
92#include <sys/socket.h>
93#include <sys/sockio.h>
94#include <sys/kernel.h>
95#include <sys/malloc.h>
96
97#include <machine/clock.h>
98#include <machine/bus.h>
99#include <machine/resource.h>
100#include <sys/rman.h>
101
102#include <net/if.h>
103#include <net/if_types.h>
104#include <net/netisr.h>
105
106#include <netinet/in.h>
107#include <netinet/in_var.h>
108
109#include <net/bpf.h>
110
111#include <dev/ppbus/ppbconf.h>
112#include "ppbus_if.h"
113#include <dev/ppbus/ppbio.h>
114
115#ifndef LPMTU			/* MTU for the lp# interfaces */
116#define	LPMTU	1500
117#endif
118
119#ifndef LPMAXSPIN1		/* DELAY factor for the lp# interfaces */
120#define	LPMAXSPIN1	8000   /* Spinning for remote intr to happen */
121#endif
122
123#ifndef LPMAXSPIN2		/* DELAY factor for the lp# interfaces */
124#define	LPMAXSPIN2	500	/* Spinning for remote handshake to happen */
125#endif
126
127#ifndef LPMAXERRS		/* Max errors before !RUNNING */
128#define	LPMAXERRS	100
129#endif
130
131#define CLPIPHDRLEN	14	/* We send dummy ethernet addresses (two) + packet type in front of packet */
132#define	CLPIP_SHAKE	0x80	/* This bit toggles between nibble reception */
133#define MLPIPHDRLEN	CLPIPHDRLEN
134
135#define LPIPHDRLEN	2	/* We send 0x08, 0x00 in front of packet */
136#define	LPIP_SHAKE	0x40	/* This bit toggles between nibble reception */
137#if !defined(MLPIPHDRLEN) || LPIPHDRLEN > MLPIPHDRLEN
138#define MLPIPHDRLEN	LPIPHDRLEN
139#endif
140
141#define	LPIPTBLSIZE	256	/* Size of octet translation table */
142
143#define lprintf		if (lptflag) printf
144
145#ifdef PLIP_DEBUG
146static int volatile lptflag = 1;
147#else
148static int volatile lptflag = 0;
149#endif
150
151struct lp_data {
152	unsigned short lp_unit;
153
154	struct  ifnet	sc_if;
155	u_char		*sc_ifbuf;
156	int		sc_iferrs;
157
158	struct resource *res_irq;
159};
160
161/* Tables for the lp# interface */
162static u_char *txmith;
163#define txmitl (txmith+(1*LPIPTBLSIZE))
164#define trecvh (txmith+(2*LPIPTBLSIZE))
165#define trecvl (txmith+(3*LPIPTBLSIZE))
166
167static u_char *ctxmith;
168#define ctxmitl (ctxmith+(1*LPIPTBLSIZE))
169#define ctrecvh (ctxmith+(2*LPIPTBLSIZE))
170#define ctrecvl (ctxmith+(3*LPIPTBLSIZE))
171
172/* Functions for the lp# interface */
173static int lp_probe(device_t dev);
174static int lp_attach(device_t dev);
175
176static int lpinittables(void);
177static int lpioctl(struct ifnet *, u_long, caddr_t);
178static int lpoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
179	struct rtentry *);
180static void lp_intr(void *);
181
182#define DEVTOSOFTC(dev) \
183	((struct lp_data *)device_get_softc(dev))
184#define UNITOSOFTC(unit) \
185	((struct lp_data *)devclass_get_softc(lp_devclass, (unit)))
186#define UNITODEVICE(unit) \
187	(devclass_get_device(lp_devclass, (unit)))
188
189static devclass_t lp_devclass;
190
191static device_method_t lp_methods[] = {
192  	/* device interface */
193	DEVMETHOD(device_probe,		lp_probe),
194	DEVMETHOD(device_attach,	lp_attach),
195
196	{ 0, 0 }
197};
198
199static driver_t lp_driver = {
200  "plip",
201  lp_methods,
202  sizeof(struct lp_data),
203};
204
205/*
206 * lpprobe()
207 */
208static int
209lp_probe(device_t dev)
210{
211	device_t ppbus = device_get_parent(dev);
212	struct lp_data *lp;
213	int irq, zero = 0;
214
215	lp = DEVTOSOFTC(dev);
216	bzero(lp, sizeof(struct lp_data));
217
218	/* retrieve the ppbus irq */
219	BUS_READ_IVAR(ppbus, dev, PPBUS_IVAR_IRQ, &irq);
220
221	/* if we haven't interrupts, the probe fails */
222	if (irq == -1) {
223		device_printf(dev, "not an interrupt driven port, failed.\n");
224		return (ENXIO);
225	}
226
227	/* reserve the interrupt resource, expecting irq is available to continue */
228	lp->res_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &zero, irq, irq, 1,
229					 RF_SHAREABLE);
230	if (lp->res_irq == 0) {
231		device_printf(dev, "cannot reserve interrupt, failed.\n");
232		return (ENXIO);
233	}
234
235	/*
236	 * lp dependent initialisation.
237	 */
238	lp->lp_unit = device_get_unit(dev);
239
240	device_set_desc(dev, "PLIP network interface");
241
242	return (0);
243}
244
245static int
246lp_attach (device_t dev)
247{
248	struct lp_data *lp = DEVTOSOFTC(dev);
249	struct ifnet *ifp = &lp->sc_if;
250
251	ifp->if_softc = lp;
252	ifp->if_name = "lp";
253	ifp->if_unit = device_get_unit(dev);
254	ifp->if_mtu = LPMTU;
255	ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST;
256	ifp->if_ioctl = lpioctl;
257	ifp->if_output = lpoutput;
258	ifp->if_type = IFT_PARA;
259	ifp->if_hdrlen = 0;
260	ifp->if_addrlen = 0;
261	ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
262	if_attach(ifp);
263
264	bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
265
266	return (0);
267}
268/*
269 * Build the translation tables for the LPIP (BSD unix) protocol.
270 * We don't want to calculate these nasties in our tight loop, so we
271 * precalculate them when we initialize.
272 */
273static int
274lpinittables (void)
275{
276    int i;
277
278    if (!txmith)
279	txmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT);
280
281    if (!txmith)
282	return 1;
283
284    if (!ctxmith)
285	ctxmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT);
286
287    if (!ctxmith)
288	return 1;
289
290    for (i=0; i < LPIPTBLSIZE; i++) {
291	ctxmith[i] = (i & 0xF0) >> 4;
292	ctxmitl[i] = 0x10 | (i & 0x0F);
293	ctrecvh[i] = (i & 0x78) << 1;
294	ctrecvl[i] = (i & 0x78) >> 3;
295    }
296
297    for (i=0; i < LPIPTBLSIZE; i++) {
298	txmith[i] = ((i & 0x80) >> 3) | ((i & 0x70) >> 4) | 0x08;
299	txmitl[i] = ((i & 0x08) << 1) | (i & 0x07);
300	trecvh[i] = ((~i) & 0x80) | ((i & 0x38) << 1);
301	trecvl[i] = (((~i) & 0x80) >> 4) | ((i & 0x38) >> 3);
302    }
303
304    return 0;
305}
306
307/*
308 * Process an ioctl request.
309 */
310
311static int
312lpioctl (struct ifnet *ifp, u_long cmd, caddr_t data)
313{
314    device_t dev = UNITODEVICE(ifp->if_unit);
315    device_t ppbus = device_get_parent(dev);
316    struct lp_data *sc = DEVTOSOFTC(dev);
317    struct ifaddr *ifa = (struct ifaddr *)data;
318    struct ifreq *ifr = (struct ifreq *)data;
319    u_char *ptr;
320    void *ih;
321    int error;
322
323    switch (cmd) {
324
325    case SIOCSIFDSTADDR:
326    case SIOCAIFADDR:
327    case SIOCSIFADDR:
328	if (ifa->ifa_addr->sa_family != AF_INET)
329	    return EAFNOSUPPORT;
330
331	ifp->if_flags |= IFF_UP;
332	/* FALLTHROUGH */
333    case SIOCSIFFLAGS:
334	if ((!(ifp->if_flags & IFF_UP)) && (ifp->if_flags & IFF_RUNNING)) {
335
336	    ppb_wctr(ppbus, 0x00);
337	    ifp->if_flags &= ~IFF_RUNNING;
338
339	    /* IFF_UP is not set, try to release the bus anyway */
340	    ppb_release_bus(ppbus, dev);
341	    break;
342	}
343	if (((ifp->if_flags & IFF_UP)) && (!(ifp->if_flags & IFF_RUNNING))) {
344
345	    /* XXX
346	     * Should the request be interruptible?
347	     */
348	    if ((error = ppb_request_bus(ppbus, dev, PPB_WAIT|PPB_INTR)))
349		return (error);
350
351	    /* Now IFF_UP means that we own the bus */
352
353	    ppb_set_mode(ppbus, PPB_COMPATIBLE);
354
355	    if (lpinittables()) {
356		ppb_release_bus(ppbus, dev);
357		return ENOBUFS;
358	    }
359
360	    sc->sc_ifbuf = malloc(sc->sc_if.if_mtu + MLPIPHDRLEN,
361				  M_DEVBUF, M_WAITOK);
362	    if (!sc->sc_ifbuf) {
363		ppb_release_bus(ppbus, dev);
364		return ENOBUFS;
365	    }
366
367	    /* attach our interrupt handler, later detached when the bus is released */
368	    if ((error = BUS_SETUP_INTR(ppbus, dev, sc->res_irq,
369					INTR_TYPE_NET, lp_intr, dev, &ih))) {
370		ppb_release_bus(ppbus, dev);
371		return (error);
372	    }
373
374	    ppb_wctr(ppbus, IRQENABLE);
375	    ifp->if_flags |= IFF_RUNNING;
376	}
377	break;
378
379    case SIOCSIFMTU:
380	ptr = sc->sc_ifbuf;
381	sc->sc_ifbuf = malloc(ifr->ifr_mtu+MLPIPHDRLEN, M_DEVBUF, M_NOWAIT);
382	if (!sc->sc_ifbuf) {
383	    sc->sc_ifbuf = ptr;
384	    return ENOBUFS;
385	}
386	if (ptr)
387	    free(ptr,M_DEVBUF);
388	sc->sc_if.if_mtu = ifr->ifr_mtu;
389	break;
390
391    case SIOCGIFMTU:
392	ifr->ifr_mtu = sc->sc_if.if_mtu;
393	break;
394
395    case SIOCADDMULTI:
396    case SIOCDELMULTI:
397	if (ifr == 0) {
398	    return EAFNOSUPPORT;		/* XXX */
399	}
400	switch (ifr->ifr_addr.sa_family) {
401
402	case AF_INET:
403	    break;
404
405	default:
406	    return EAFNOSUPPORT;
407	}
408	break;
409
410    case SIOCGIFMEDIA:
411	/*
412	 * No ifmedia support at this stage; maybe use it
413	 * in future for eg. protocol selection.
414	 */
415	return EINVAL;
416
417    default:
418	lprintf("LP:ioctl(0x%lx)\n", cmd);
419	return EINVAL;
420    }
421    return 0;
422}
423
424static __inline int
425clpoutbyte (u_char byte, int spin, device_t ppbus)
426{
427	ppb_wdtr(ppbus, ctxmitl[byte]);
428	while (ppb_rstr(ppbus) & CLPIP_SHAKE)
429		if (--spin == 0) {
430			return 1;
431		}
432	ppb_wdtr(ppbus, ctxmith[byte]);
433	while (!(ppb_rstr(ppbus) & CLPIP_SHAKE))
434		if (--spin == 0) {
435			return 1;
436		}
437	return 0;
438}
439
440static __inline int
441clpinbyte (int spin, device_t ppbus)
442{
443	u_char c, cl;
444
445	while((ppb_rstr(ppbus) & CLPIP_SHAKE))
446	    if(!--spin) {
447		return -1;
448	    }
449	cl = ppb_rstr(ppbus);
450	ppb_wdtr(ppbus, 0x10);
451
452	while(!(ppb_rstr(ppbus) & CLPIP_SHAKE))
453	    if(!--spin) {
454		return -1;
455	    }
456	c = ppb_rstr(ppbus);
457	ppb_wdtr(ppbus, 0x00);
458
459	return (ctrecvl[cl] | ctrecvh[c]);
460}
461
462static void
463lptap(struct ifnet *ifp, struct mbuf *m)
464{
465	/*
466	 * Send a packet through bpf. We need to prepend the address family
467	 * as a four byte field. Cons up a dummy header to pacify bpf. This
468	 * is safe because bpf will only read from the mbuf (i.e., it won't
469	 * try to free it or keep a pointer to it).
470	 */
471	u_int32_t af = AF_INET;
472	struct mbuf m0;
473
474	m0.m_next = m;
475	m0.m_len = sizeof(u_int32_t);
476	m0.m_data = (char *)&af;
477	bpf_mtap(ifp, &m0);
478}
479
480static void
481lp_intr (void *arg)
482{
483	device_t dev = (device_t)arg;
484        device_t ppbus = device_get_parent(dev);
485	struct lp_data *sc = DEVTOSOFTC(dev);
486	int len, s, j;
487	u_char *bp;
488	u_char c, cl;
489	struct mbuf *top;
490
491	s = splhigh();
492
493	if (sc->sc_if.if_flags & IFF_LINK0) {
494
495	    /* Ack. the request */
496	    ppb_wdtr(ppbus, 0x01);
497
498	    /* Get the packet length */
499	    j = clpinbyte(LPMAXSPIN2, ppbus);
500	    if (j == -1)
501		goto err;
502	    len = j;
503	    j = clpinbyte(LPMAXSPIN2, ppbus);
504	    if (j == -1)
505		goto err;
506	    len = len + (j << 8);
507	    if (len > sc->sc_if.if_mtu + MLPIPHDRLEN)
508		goto err;
509
510	    bp  = sc->sc_ifbuf;
511
512	    while (len--) {
513	        j = clpinbyte(LPMAXSPIN2, ppbus);
514	        if (j == -1) {
515		    goto err;
516	        }
517	        *bp++ = j;
518	    }
519	    /* Get and ignore checksum */
520	    j = clpinbyte(LPMAXSPIN2, ppbus);
521	    if (j == -1) {
522	        goto err;
523	    }
524
525	    len = bp - sc->sc_ifbuf;
526	    if (len <= CLPIPHDRLEN)
527	        goto err;
528
529	    sc->sc_iferrs = 0;
530
531	    if (IF_QFULL(&ipintrq)) {
532	        lprintf("DROP");
533	        IF_DROP(&ipintrq);
534		goto done;
535	    }
536	    len -= CLPIPHDRLEN;
537	    sc->sc_if.if_ipackets++;
538	    sc->sc_if.if_ibytes += len;
539	    top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, &sc->sc_if, 0);
540	    if (top) {
541		if (sc->sc_if.if_bpf)
542		    lptap(&sc->sc_if, top);
543	        IF_ENQUEUE(&ipintrq, top);
544	        schednetisr(NETISR_IP);
545	    }
546	    goto done;
547	}
548	while ((ppb_rstr(ppbus) & LPIP_SHAKE)) {
549	    len = sc->sc_if.if_mtu + LPIPHDRLEN;
550	    bp  = sc->sc_ifbuf;
551	    while (len--) {
552
553		cl = ppb_rstr(ppbus);
554		ppb_wdtr(ppbus, 8);
555
556		j = LPMAXSPIN2;
557		while((ppb_rstr(ppbus) & LPIP_SHAKE))
558		    if(!--j) goto err;
559
560		c = ppb_rstr(ppbus);
561		ppb_wdtr(ppbus, 0);
562
563		*bp++= trecvh[cl] | trecvl[c];
564
565		j = LPMAXSPIN2;
566		while (!((cl=ppb_rstr(ppbus)) & LPIP_SHAKE)) {
567		    if (cl != c &&
568			(((cl = ppb_rstr(ppbus)) ^ 0xb8) & 0xf8) ==
569			  (c & 0xf8))
570			goto end;
571		    if (!--j) goto err;
572		}
573	    }
574
575	end:
576	    len = bp - sc->sc_ifbuf;
577	    if (len <= LPIPHDRLEN)
578		goto err;
579
580	    sc->sc_iferrs = 0;
581
582	    if (IF_QFULL(&ipintrq)) {
583		lprintf("DROP");
584		IF_DROP(&ipintrq);
585		goto done;
586	    }
587	    len -= LPIPHDRLEN;
588	    sc->sc_if.if_ipackets++;
589	    sc->sc_if.if_ibytes += len;
590	    top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, &sc->sc_if, 0);
591	    if (top) {
592		if (sc->sc_if.if_bpf)
593		    lptap(&sc->sc_if, top);
594		IF_ENQUEUE(&ipintrq, top);
595		schednetisr(NETISR_IP);
596	    }
597	}
598	goto done;
599
600    err:
601	ppb_wdtr(ppbus, 0);
602	lprintf("R");
603	sc->sc_if.if_ierrors++;
604	sc->sc_iferrs++;
605
606	/*
607	 * We are not able to send receive anything for now,
608	 * so stop wasting our time
609	 */
610	if (sc->sc_iferrs > LPMAXERRS) {
611	    printf("lp%d: Too many errors, Going off-line.\n", device_get_unit(dev));
612	    ppb_wctr(ppbus, 0x00);
613	    sc->sc_if.if_flags &= ~IFF_RUNNING;
614	    sc->sc_iferrs=0;
615	}
616
617    done:
618	splx(s);
619	return;
620}
621
622static __inline int
623lpoutbyte (u_char byte, int spin, device_t ppbus)
624{
625    ppb_wdtr(ppbus, txmith[byte]);
626    while (!(ppb_rstr(ppbus) & LPIP_SHAKE))
627	if (--spin == 0)
628		return 1;
629    ppb_wdtr(ppbus, txmitl[byte]);
630    while (ppb_rstr(ppbus) & LPIP_SHAKE)
631	if (--spin == 0)
632		return 1;
633    return 0;
634}
635
636static int
637lpoutput (struct ifnet *ifp, struct mbuf *m,
638	  struct sockaddr *dst, struct rtentry *rt)
639{
640    device_t dev = UNITODEVICE(ifp->if_unit);
641    device_t ppbus = device_get_parent(dev);
642    int s, err;
643    struct mbuf *mm;
644    u_char *cp = "\0\0";
645    u_char chksum = 0;
646    int count = 0;
647    int i, len, spin;
648
649    /* We need a sensible value if we abort */
650    cp++;
651    ifp->if_flags |= IFF_RUNNING;
652
653    err = 1;			/* assume we're aborting because of an error */
654
655    s = splhigh();
656
657    /* Suspend (on laptops) or receive-errors might have taken us offline */
658    ppb_wctr(ppbus, IRQENABLE);
659
660    if (ifp->if_flags & IFF_LINK0) {
661
662	if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) {
663	    lprintf("&");
664	    lp_intr(dev);
665	}
666
667	/* Alert other end to pending packet */
668	spin = LPMAXSPIN1;
669	ppb_wdtr(ppbus, 0x08);
670	while ((ppb_rstr(ppbus) & 0x08) == 0)
671		if (--spin == 0) {
672			goto nend;
673		}
674
675	/* Calculate length of packet, then send that */
676
677	count += 14;		/* Ethernet header len */
678
679	mm = m;
680	for (mm = m; mm; mm = mm->m_next) {
681		count += mm->m_len;
682	}
683	if (clpoutbyte(count & 0xFF, LPMAXSPIN1, ppbus))
684		goto nend;
685	if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, ppbus))
686		goto nend;
687
688	/* Send dummy ethernet header */
689	for (i = 0; i < 12; i++) {
690		if (clpoutbyte(i, LPMAXSPIN1, ppbus))
691			goto nend;
692		chksum += i;
693	}
694
695	if (clpoutbyte(0x08, LPMAXSPIN1, ppbus))
696		goto nend;
697	if (clpoutbyte(0x00, LPMAXSPIN1, ppbus))
698		goto nend;
699	chksum += 0x08 + 0x00;		/* Add into checksum */
700
701	mm = m;
702	do {
703		cp = mtod(mm, u_char *);
704		len = mm->m_len;
705		while (len--) {
706			chksum += *cp;
707			if (clpoutbyte(*cp++, LPMAXSPIN2, ppbus))
708				goto nend;
709		}
710	} while ((mm = mm->m_next));
711
712	/* Send checksum */
713	if (clpoutbyte(chksum, LPMAXSPIN2, ppbus))
714		goto nend;
715
716	/* Go quiescent */
717	ppb_wdtr(ppbus, 0);
718
719	err = 0;			/* No errors */
720
721	nend:
722	if (err)  {				/* if we didn't timeout... */
723		ifp->if_oerrors++;
724		lprintf("X");
725	} else {
726		ifp->if_opackets++;
727		ifp->if_obytes += m->m_pkthdr.len;
728		if (ifp->if_bpf)
729		    lptap(ifp, m);
730	}
731
732	m_freem(m);
733
734	if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) {
735		lprintf("^");
736		lp_intr(dev);
737	}
738	(void) splx(s);
739	return 0;
740    }
741
742    if (ppb_rstr(ppbus) & LPIP_SHAKE) {
743        lprintf("&");
744        lp_intr(dev);
745    }
746
747    if (lpoutbyte(0x08, LPMAXSPIN1, ppbus))
748        goto end;
749    if (lpoutbyte(0x00, LPMAXSPIN2, ppbus))
750        goto end;
751
752    mm = m;
753    do {
754        cp = mtod(mm,u_char *);
755	len = mm->m_len;
756        while (len--)
757	    if (lpoutbyte(*cp++, LPMAXSPIN2, ppbus))
758	        goto end;
759    } while ((mm = mm->m_next));
760
761    err = 0;				/* no errors were encountered */
762
763    end:
764    --cp;
765    ppb_wdtr(ppbus, txmitl[*cp] ^ 0x17);
766
767    if (err)  {				/* if we didn't timeout... */
768	ifp->if_oerrors++;
769        lprintf("X");
770    } else {
771	ifp->if_opackets++;
772	ifp->if_obytes += m->m_pkthdr.len;
773	if (ifp->if_bpf)
774	    lptap(ifp, m);
775    }
776
777    m_freem(m);
778
779    if (ppb_rstr(ppbus) & LPIP_SHAKE) {
780	lprintf("^");
781	lp_intr(dev);
782    }
783
784    (void) splx(s);
785    return 0;
786}
787
788DRIVER_MODULE(plip, ppbus, lp_driver, lp_devclass, 0, 0);
789
790#endif /* NPLIP > 0 */
791