if_plip.c revision 185003
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 185003 2008-11-16 17:42:02Z 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	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 */
158static u_char *txmith;
159#define	txmitl (txmith + (1 * LPIPTBLSIZE))
160#define	trecvh (txmith + (2 * LPIPTBLSIZE))
161#define	trecvl (txmith + (3 * LPIPTBLSIZE))
162
163static 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 */
169static int lpinittables(void);
170static int lpioctl(struct ifnet *, u_long, caddr_t);
171static int lpoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
172	struct rtentry *);
173static void lp_intr(void *);
174
175#define	DEVTOSOFTC(dev) \
176	((struct lp_data *)device_get_softc(dev))
177
178static devclass_t lp_devclass;
179
180static void
181lp_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
190static int
191lp_probe(device_t dev)
192{
193
194	device_set_desc(dev, "PLIP network interface");
195
196	return (0);
197}
198
199static int
200lp_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 */
245static int
246lpinittables(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 */
282static int
283lpioctl(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
398static __inline int
399clpoutbyte(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
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
442	bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m);
443}
444
445static void
446lp_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
562err:
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
579done:
580	splx(s);
581}
582
583static __inline int
584lpoutbyte(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
598static int
599lpoutput(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
725end:
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
750static 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
759static driver_t lp_driver = {
760	"plip",
761	lp_methods,
762	sizeof(struct lp_data),
763};
764
765DRIVER_MODULE(plip, ppbus, lp_driver, lp_devclass, 0, 0);
766MODULE_DEPEND(plip, ppbus, 1, 1, 1);
767