if_plip.c revision 183053
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: head/sys/dev/ppbus/if_plip.c 183053 2008-09-15 22:26:32Z jhb $");
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
143static int volatile lptflag = 1;
144#else
145static int volatile lptflag = 0;
146#endif
147
148struct lp_data {
149	struct  ifnet	*sc_ifp;
150	u_char		*sc_ifbuf;
151	int		sc_iferrs;
152
153	struct resource *res_irq;
154};
155
156/* Tables for the lp# interface */
157static u_char *txmith;
158#define txmitl (txmith+(1*LPIPTBLSIZE))
159#define trecvh (txmith+(2*LPIPTBLSIZE))
160#define trecvl (txmith+(3*LPIPTBLSIZE))
161
162static u_char *ctxmith;
163#define ctxmitl (ctxmith+(1*LPIPTBLSIZE))
164#define ctrecvh (ctxmith+(2*LPIPTBLSIZE))
165#define ctrecvl (ctxmith+(3*LPIPTBLSIZE))
166
167/* Functions for the lp# interface */
168static int lpinittables(void);
169static int lpioctl(struct ifnet *, u_long, caddr_t);
170static int lpoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
171	struct rtentry *);
172static void lp_intr(void *);
173
174#define DEVTOSOFTC(dev) \
175	((struct lp_data *)device_get_softc(dev))
176#define UNITODEVICE(unit) \
177	(devclass_get_device(lp_devclass, (unit)))
178
179static devclass_t lp_devclass;
180
181static void
182lp_identify(driver_t *driver, device_t parent)
183{
184	device_t dev;
185
186	dev = device_find_child(parent, "plip", -1);
187	if (!dev)
188		BUS_ADD_CHILD(parent, 0, "plip", -1);
189}
190/*
191 * lpprobe()
192 */
193static int
194lp_probe(device_t dev)
195{
196
197	device_set_desc(dev, "PLIP network interface");
198
199	return (0);
200}
201
202static int
203lp_attach (device_t dev)
204{
205	struct lp_data *lp = DEVTOSOFTC(dev);
206	struct ifnet *ifp;
207	int rid = 0;
208
209	/*
210	 * Reserve the interrupt resource.  If we don't have one, the
211	 * attach fails.
212	 */
213	lp->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
214	    RF_SHAREABLE);
215	if (lp->res_irq == 0) {
216		device_printf(dev, "cannot reserve interrupt, failed.\n");
217		return (ENXIO);
218	}
219
220	ifp = lp->sc_ifp = if_alloc(IFT_PARA);
221	if (ifp == NULL) {
222		return (ENOSPC);
223	}
224
225	ifp->if_softc = lp;
226	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
227	ifp->if_mtu = LPMTU;
228	ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST |
229	    IFF_NEEDSGIANT;
230	ifp->if_ioctl = lpioctl;
231	ifp->if_output = lpoutput;
232	ifp->if_hdrlen = 0;
233	ifp->if_addrlen = 0;
234	ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
235	if_attach(ifp);
236
237	bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
238
239	return (0);
240}
241/*
242 * Build the translation tables for the LPIP (BSD unix) protocol.
243 * We don't want to calculate these nasties in our tight loop, so we
244 * precalculate them when we initialize.
245 */
246static int
247lpinittables (void)
248{
249    int i;
250
251    if (!txmith)
252	txmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT);
253
254    if (!txmith)
255	return 1;
256
257    if (!ctxmith)
258	ctxmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT);
259
260    if (!ctxmith)
261	return 1;
262
263    for (i=0; i < LPIPTBLSIZE; i++) {
264	ctxmith[i] = (i & 0xF0) >> 4;
265	ctxmitl[i] = 0x10 | (i & 0x0F);
266	ctrecvh[i] = (i & 0x78) << 1;
267	ctrecvl[i] = (i & 0x78) >> 3;
268    }
269
270    for (i=0; i < LPIPTBLSIZE; i++) {
271	txmith[i] = ((i & 0x80) >> 3) | ((i & 0x70) >> 4) | 0x08;
272	txmitl[i] = ((i & 0x08) << 1) | (i & 0x07);
273	trecvh[i] = ((~i) & 0x80) | ((i & 0x38) << 1);
274	trecvl[i] = (((~i) & 0x80) >> 4) | ((i & 0x38) >> 3);
275    }
276
277    return 0;
278}
279
280/*
281 * Process an ioctl request.
282 */
283
284static int
285lpioctl (struct ifnet *ifp, u_long cmd, caddr_t data)
286{
287    device_t dev = UNITODEVICE(ifp->if_dunit);
288    device_t ppbus = device_get_parent(dev);
289    struct lp_data *sc = DEVTOSOFTC(dev);
290    struct ifaddr *ifa = (struct ifaddr *)data;
291    struct ifreq *ifr = (struct ifreq *)data;
292    u_char *ptr;
293    void *ih;
294    int error;
295
296    switch (cmd) {
297
298    case SIOCSIFDSTADDR:
299    case SIOCAIFADDR:
300    case SIOCSIFADDR:
301	if (ifa->ifa_addr->sa_family != AF_INET)
302	    return EAFNOSUPPORT;
303
304	ifp->if_flags |= IFF_UP;
305	/* FALLTHROUGH */
306    case SIOCSIFFLAGS:
307	if ((!(ifp->if_flags & IFF_UP)) &&
308	  (ifp->if_drv_flags & IFF_DRV_RUNNING)) {
309
310	    ppb_wctr(ppbus, 0x00);
311	    ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
312
313	    /* IFF_UP is not set, try to release the bus anyway */
314	    ppb_release_bus(ppbus, dev);
315	    break;
316	}
317	if (((ifp->if_flags & IFF_UP)) &&
318	  (!(ifp->if_drv_flags & IFF_DRV_RUNNING))) {
319
320	    /* XXX
321	     * Should the request be interruptible?
322	     */
323	    if ((error = ppb_request_bus(ppbus, dev, PPB_WAIT|PPB_INTR)))
324		return (error);
325
326	    /* Now IFF_UP means that we own the bus */
327
328	    ppb_set_mode(ppbus, PPB_COMPATIBLE);
329
330	    if (lpinittables()) {
331		ppb_release_bus(ppbus, dev);
332		return ENOBUFS;
333	    }
334
335	    sc->sc_ifbuf = malloc(sc->sc_ifp->if_mtu + MLPIPHDRLEN,
336				  M_DEVBUF, M_WAITOK);
337	    if (!sc->sc_ifbuf) {
338		ppb_release_bus(ppbus, dev);
339		return ENOBUFS;
340	    }
341
342	    /* attach our interrupt handler, later detached when the bus is released */
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, M_NOWAIT);
357	if (!sc->sc_ifbuf) {
358	    sc->sc_ifbuf = ptr;
359	    return ENOBUFS;
360	}
361	if (ptr)
362	    free(ptr,M_DEVBUF);
363	sc->sc_ifp->if_mtu = ifr->ifr_mtu;
364	break;
365
366    case SIOCGIFMTU:
367	ifr->ifr_mtu = sc->sc_ifp->if_mtu;
368	break;
369
370    case SIOCADDMULTI:
371    case SIOCDELMULTI:
372	if (ifr == 0) {
373	    return EAFNOSUPPORT;		/* XXX */
374	}
375	switch (ifr->ifr_addr.sa_family) {
376
377	case AF_INET:
378	    break;
379
380	default:
381	    return EAFNOSUPPORT;
382	}
383	break;
384
385    case SIOCGIFMEDIA:
386	/*
387	 * No ifmedia support at this stage; maybe use it
388	 * in future for eg. protocol selection.
389	 */
390	return EINVAL;
391
392    default:
393	lprintf("LP:ioctl(0x%lx)\n", cmd);
394	return EINVAL;
395    }
396    return 0;
397}
398
399static __inline int
400clpoutbyte (u_char byte, int spin, device_t ppbus)
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
415static __inline int
416clpinbyte (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
437static void
438lptap(struct ifnet *ifp, struct mbuf *m)
439{
440	u_int32_t af = AF_INET;
441	bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m);
442}
443
444static void
445lp_intr (void *arg)
446{
447	device_t dev = (device_t)arg;
448        device_t ppbus = device_get_parent(dev);
449	struct lp_data *sc = DEVTOSOFTC(dev);
450	int len, s, j;
451	u_char *bp;
452	u_char c, cl;
453	struct mbuf *top;
454
455	s = splhigh();
456
457	if (sc->sc_ifp->if_flags & IFF_LINK0) {
458
459	    /* Ack. the request */
460	    ppb_wdtr(ppbus, 0x01);
461
462	    /* Get the packet length */
463	    j = clpinbyte(LPMAXSPIN2, ppbus);
464	    if (j == -1)
465		goto err;
466	    len = j;
467	    j = clpinbyte(LPMAXSPIN2, ppbus);
468	    if (j == -1)
469		goto err;
470	    len = len + (j << 8);
471	    if (len > sc->sc_ifp->if_mtu + MLPIPHDRLEN)
472		goto err;
473
474	    bp  = sc->sc_ifbuf;
475
476	    while (len--) {
477	        j = clpinbyte(LPMAXSPIN2, ppbus);
478	        if (j == -1) {
479		    goto err;
480	        }
481	        *bp++ = j;
482	    }
483	    /* Get and ignore checksum */
484	    j = clpinbyte(LPMAXSPIN2, ppbus);
485	    if (j == -1) {
486	        goto err;
487	    }
488
489	    len = bp - sc->sc_ifbuf;
490	    if (len <= CLPIPHDRLEN)
491	        goto err;
492
493	    sc->sc_iferrs = 0;
494
495	    len -= CLPIPHDRLEN;
496	    sc->sc_ifp->if_ipackets++;
497	    sc->sc_ifp->if_ibytes += len;
498	    top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, sc->sc_ifp, 0);
499	    if (top) {
500		if (bpf_peers_present(sc->sc_ifp->if_bpf))
501		    lptap(sc->sc_ifp, top);
502		netisr_queue(NETISR_IP, top);	/* mbuf is free'd on failure. */
503	    }
504	    goto done;
505	}
506	while ((ppb_rstr(ppbus) & LPIP_SHAKE)) {
507	    len = sc->sc_ifp->if_mtu + LPIPHDRLEN;
508	    bp  = sc->sc_ifbuf;
509	    while (len--) {
510
511		cl = ppb_rstr(ppbus);
512		ppb_wdtr(ppbus, 8);
513
514		j = LPMAXSPIN2;
515		while((ppb_rstr(ppbus) & LPIP_SHAKE))
516		    if(!--j) goto err;
517
518		c = ppb_rstr(ppbus);
519		ppb_wdtr(ppbus, 0);
520
521		*bp++= trecvh[cl] | trecvl[c];
522
523		j = LPMAXSPIN2;
524		while (!((cl=ppb_rstr(ppbus)) & LPIP_SHAKE)) {
525		    if (cl != c &&
526			(((cl = ppb_rstr(ppbus)) ^ 0xb8) & 0xf8) ==
527			  (c & 0xf8))
528			goto end;
529		    if (!--j) goto err;
530		}
531	    }
532
533	end:
534	    len = bp - sc->sc_ifbuf;
535	    if (len <= LPIPHDRLEN)
536		goto err;
537
538	    sc->sc_iferrs = 0;
539
540	    len -= LPIPHDRLEN;
541	    sc->sc_ifp->if_ipackets++;
542	    sc->sc_ifp->if_ibytes += len;
543	    top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, sc->sc_ifp, 0);
544	    if (top) {
545		if (bpf_peers_present(sc->sc_ifp->if_bpf))
546		    lptap(sc->sc_ifp, top);
547		netisr_queue(NETISR_IP, top);	/* mbuf is free'd on failure. */
548	    }
549	}
550	goto done;
551
552    err:
553	ppb_wdtr(ppbus, 0);
554	lprintf("R");
555	sc->sc_ifp->if_ierrors++;
556	sc->sc_iferrs++;
557
558	/*
559	 * We are not able to send receive anything for now,
560	 * so stop wasting our time
561	 */
562	if (sc->sc_iferrs > LPMAXERRS) {
563	    printf("lp%d: Too many errors, Going off-line.\n", device_get_unit(dev));
564	    ppb_wctr(ppbus, 0x00);
565	    sc->sc_ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
566	    sc->sc_iferrs=0;
567	}
568
569    done:
570	splx(s);
571	return;
572}
573
574static __inline int
575lpoutbyte (u_char byte, int spin, device_t ppbus)
576{
577    ppb_wdtr(ppbus, txmith[byte]);
578    while (!(ppb_rstr(ppbus) & LPIP_SHAKE))
579	if (--spin == 0)
580		return 1;
581    ppb_wdtr(ppbus, txmitl[byte]);
582    while (ppb_rstr(ppbus) & LPIP_SHAKE)
583	if (--spin == 0)
584		return 1;
585    return 0;
586}
587
588static int
589lpoutput (struct ifnet *ifp, struct mbuf *m,
590	  struct sockaddr *dst, struct rtentry *rt)
591{
592    device_t dev = UNITODEVICE(ifp->if_dunit);
593    device_t ppbus = device_get_parent(dev);
594    int s, err;
595    struct mbuf *mm;
596    u_char *cp = "\0\0";
597    u_char chksum = 0;
598    int count = 0;
599    int i, len, spin;
600
601    /* We need a sensible value if we abort */
602    cp++;
603    ifp->if_drv_flags |= IFF_DRV_RUNNING;
604
605    err = 1;			/* assume we're aborting because of an error */
606
607    s = splhigh();
608
609    /* Suspend (on laptops) or receive-errors might have taken us offline */
610    ppb_wctr(ppbus, IRQENABLE);
611
612    if (ifp->if_flags & IFF_LINK0) {
613
614	if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) {
615	    lprintf("&");
616	    lp_intr(dev);
617	}
618
619	/* Alert other end to pending packet */
620	spin = LPMAXSPIN1;
621	ppb_wdtr(ppbus, 0x08);
622	while ((ppb_rstr(ppbus) & 0x08) == 0)
623		if (--spin == 0) {
624			goto nend;
625		}
626
627	/* Calculate length of packet, then send that */
628
629	count += 14;		/* Ethernet header len */
630
631	mm = m;
632	for (mm = m; mm; mm = mm->m_next) {
633		count += mm->m_len;
634	}
635	if (clpoutbyte(count & 0xFF, LPMAXSPIN1, ppbus))
636		goto nend;
637	if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, ppbus))
638		goto nend;
639
640	/* Send dummy ethernet header */
641	for (i = 0; i < 12; i++) {
642		if (clpoutbyte(i, LPMAXSPIN1, ppbus))
643			goto nend;
644		chksum += i;
645	}
646
647	if (clpoutbyte(0x08, LPMAXSPIN1, ppbus))
648		goto nend;
649	if (clpoutbyte(0x00, LPMAXSPIN1, ppbus))
650		goto nend;
651	chksum += 0x08 + 0x00;		/* Add into checksum */
652
653	mm = m;
654	do {
655		cp = mtod(mm, u_char *);
656		len = mm->m_len;
657		while (len--) {
658			chksum += *cp;
659			if (clpoutbyte(*cp++, LPMAXSPIN2, ppbus))
660				goto nend;
661		}
662	} while ((mm = mm->m_next));
663
664	/* Send checksum */
665	if (clpoutbyte(chksum, LPMAXSPIN2, ppbus))
666		goto nend;
667
668	/* Go quiescent */
669	ppb_wdtr(ppbus, 0);
670
671	err = 0;			/* No errors */
672
673	nend:
674	if (err)  {				/* if we didn't timeout... */
675		ifp->if_oerrors++;
676		lprintf("X");
677	} else {
678		ifp->if_opackets++;
679		ifp->if_obytes += m->m_pkthdr.len;
680		if (bpf_peers_present(ifp->if_bpf))
681		    lptap(ifp, m);
682	}
683
684	m_freem(m);
685
686	if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) {
687		lprintf("^");
688		lp_intr(dev);
689	}
690	(void) splx(s);
691	return 0;
692    }
693
694    if (ppb_rstr(ppbus) & LPIP_SHAKE) {
695        lprintf("&");
696        lp_intr(dev);
697    }
698
699    if (lpoutbyte(0x08, LPMAXSPIN1, ppbus))
700        goto end;
701    if (lpoutbyte(0x00, LPMAXSPIN2, ppbus))
702        goto end;
703
704    mm = m;
705    do {
706        cp = mtod(mm,u_char *);
707	len = mm->m_len;
708        while (len--)
709	    if (lpoutbyte(*cp++, LPMAXSPIN2, ppbus))
710	        goto end;
711    } while ((mm = mm->m_next));
712
713    err = 0;				/* no errors were encountered */
714
715    end:
716    --cp;
717    ppb_wdtr(ppbus, txmitl[*cp] ^ 0x17);
718
719    if (err)  {				/* if we didn't timeout... */
720	ifp->if_oerrors++;
721        lprintf("X");
722    } else {
723	ifp->if_opackets++;
724	ifp->if_obytes += m->m_pkthdr.len;
725	if (bpf_peers_present(ifp->if_bpf))
726	    lptap(ifp, m);
727    }
728
729    m_freem(m);
730
731    if (ppb_rstr(ppbus) & LPIP_SHAKE) {
732	lprintf("^");
733	lp_intr(dev);
734    }
735
736    (void) splx(s);
737    return 0;
738}
739
740static device_method_t lp_methods[] = {
741  	/* device interface */
742	DEVMETHOD(device_identify,	lp_identify),
743	DEVMETHOD(device_probe,		lp_probe),
744	DEVMETHOD(device_attach,	lp_attach),
745
746	{ 0, 0 }
747};
748
749static driver_t lp_driver = {
750  "plip",
751  lp_methods,
752  sizeof(struct lp_data),
753};
754
755DRIVER_MODULE(plip, ppbus, lp_driver, lp_devclass, 0, 0);
756MODULE_DEPEND(plip, ppbus, 1, 1, 1);
757