if_plip.c revision 187576
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 187576 2009-01-21 23:10:06Z 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	void		*sc_intr_cookie;
156};
157
158static struct mtx lp_tables_lock;
159MTX_SYSINIT(lp_tables, &lp_tables_lock, "plip tables", MTX_DEF);
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 lpinittables(void);
174static int lpioctl(struct ifnet *, u_long, caddr_t);
175static int lpoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
176	struct rtentry *);
177static void lpstop(struct lp_data *);
178static void lp_intr(void *);
179static int lp_module_handler(module_t, int, void *);
180
181#define	DEVTOSOFTC(dev) \
182	((struct lp_data *)device_get_softc(dev))
183
184static devclass_t lp_devclass;
185
186static int
187lp_module_handler(module_t mod, int what, void *arg)
188{
189
190	switch (what) {
191	case MOD_UNLOAD:
192		mtx_lock(&lp_tables_lock);
193		if (txmith != NULL) {
194			free(txmith, M_DEVBUF);
195			txmith = NULL;
196		}
197		if (ctxmith != NULL) {
198			free(ctxmith, M_DEVBUF);
199			ctxmith = NULL;
200		}
201		mtx_unlock(&lp_tables_lock);
202		break;
203	case MOD_LOAD:
204	case MOD_QUIESCE:
205		break;
206	default:
207		return (EOPNOTSUPP);
208	}
209	return (0);
210}
211
212static void
213lp_identify(driver_t *driver, device_t parent)
214{
215	device_t dev;
216
217	dev = device_find_child(parent, "plip", -1);
218	if (!dev)
219		BUS_ADD_CHILD(parent, 0, "plip", -1);
220}
221
222static int
223lp_probe(device_t dev)
224{
225
226	device_set_desc(dev, "PLIP network interface");
227
228	return (0);
229}
230
231static int
232lp_attach(device_t dev)
233{
234	struct lp_data *lp = DEVTOSOFTC(dev);
235	struct ifnet *ifp;
236	int error, rid = 0;
237
238	lp->sc_dev = dev;
239
240	/*
241	 * Reserve the interrupt resource.  If we don't have one, the
242	 * attach fails.
243	 */
244	lp->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
245	    RF_SHAREABLE);
246	if (lp->res_irq == 0) {
247		device_printf(dev, "cannot reserve interrupt, failed.\n");
248		return (ENXIO);
249	}
250
251	ifp = lp->sc_ifp = if_alloc(IFT_PARA);
252	if (ifp == NULL) {
253		return (ENOSPC);
254	}
255
256	ifp->if_softc = lp;
257	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
258	ifp->if_mtu = LPMTU;
259	ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST;
260	ifp->if_ioctl = lpioctl;
261	ifp->if_output = lpoutput;
262	ifp->if_hdrlen = 0;
263	ifp->if_addrlen = 0;
264	ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
265	if_attach(ifp);
266
267	bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
268
269	/*
270	 * Attach our interrupt handler.  It is only called while we
271	 * own the ppbus.
272	 */
273	error = bus_setup_intr(dev, lp->res_irq, INTR_TYPE_NET | INTR_MPSAFE,
274	    NULL, lp_intr, lp, &lp->sc_intr_cookie);
275	if (error) {
276		bpfdetach(ifp);
277		if_detach(ifp);
278		bus_release_resource(dev, SYS_RES_IRQ, 0, lp->res_irq);
279		device_printf(dev, "Unable to register interrupt handler\n");
280		return (error);
281	}
282
283	return (0);
284}
285
286static int
287lp_detach(device_t dev)
288{
289	struct lp_data *sc = device_get_softc(dev);
290	device_t ppbus = device_get_parent(dev);
291
292	ppb_lock(ppbus);
293	lpstop(sc);
294	ppb_unlock(ppbus);
295	bpfdetach(sc->sc_ifp);
296	if_detach(sc->sc_ifp);
297	bus_teardown_intr(dev, sc->res_irq, sc->sc_intr_cookie);
298	bus_release_resource(dev, SYS_RES_IRQ, 0, sc->res_irq);
299	return (0);
300}
301
302/*
303 * Build the translation tables for the LPIP (BSD unix) protocol.
304 * We don't want to calculate these nasties in our tight loop, so we
305 * precalculate them when we initialize.
306 */
307static int
308lpinittables(void)
309{
310	int i;
311
312	mtx_lock(&lp_tables_lock);
313	if (txmith == NULL)
314		txmith = malloc(4 * LPIPTBLSIZE, M_DEVBUF, M_NOWAIT);
315
316	if (txmith == NULL) {
317		mtx_unlock(&lp_tables_lock);
318		return (1);
319	}
320
321	if (ctxmith == NULL)
322		ctxmith = malloc(4 * LPIPTBLSIZE, M_DEVBUF, M_NOWAIT);
323
324	if (ctxmith == NULL) {
325		mtx_unlock(&lp_tables_lock);
326		return (1);
327	}
328
329	for (i = 0; i < LPIPTBLSIZE; i++) {
330		ctxmith[i] = (i & 0xF0) >> 4;
331		ctxmitl[i] = 0x10 | (i & 0x0F);
332		ctrecvh[i] = (i & 0x78) << 1;
333		ctrecvl[i] = (i & 0x78) >> 3;
334	}
335
336	for (i = 0; i < LPIPTBLSIZE; i++) {
337		txmith[i] = ((i & 0x80) >> 3) | ((i & 0x70) >> 4) | 0x08;
338		txmitl[i] = ((i & 0x08) << 1) | (i & 0x07);
339		trecvh[i] = ((~i) & 0x80) | ((i & 0x38) << 1);
340		trecvl[i] = (((~i) & 0x80) >> 4) | ((i & 0x38) >> 3);
341	}
342	mtx_unlock(&lp_tables_lock);
343
344	return (0);
345}
346
347static void
348lpstop(struct lp_data *sc)
349{
350	device_t ppbus = device_get_parent(sc->sc_dev);
351
352	ppb_assert_locked(ppbus);
353	ppb_wctr(ppbus, 0x00);
354	sc->sc_ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
355	free(sc->sc_ifbuf, M_DEVBUF);
356	sc->sc_ifbuf = NULL;
357
358	/* IFF_UP is not set, try to release the bus anyway */
359	ppb_release_bus(ppbus, sc->sc_dev);
360}
361
362static int
363lpinit_locked(struct ifnet *ifp)
364{
365	struct lp_data *sc = ifp->if_softc;
366	device_t dev = sc->sc_dev;
367	device_t ppbus = device_get_parent(dev);
368	int error;
369
370	ppb_assert_locked(ppbus);
371	error = ppb_request_bus(ppbus, dev, PPB_DONTWAIT);
372	if (error)
373		return (error);
374
375	/* Now IFF_UP means that we own the bus */
376	ppb_set_mode(ppbus, PPB_COMPATIBLE);
377
378	if (lpinittables()) {
379		ppb_release_bus(ppbus, dev);
380		return (ENOBUFS);
381	}
382
383	sc->sc_ifbuf = malloc(sc->sc_ifp->if_mtu + MLPIPHDRLEN,
384	    M_DEVBUF, M_NOWAIT);
385	if (sc->sc_ifbuf == NULL) {
386		ppb_release_bus(ppbus, dev);
387		return (ENOBUFS);
388	}
389
390	ppb_wctr(ppbus, IRQENABLE);
391
392	ifp->if_drv_flags |= IFF_DRV_RUNNING;
393	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
394	return (0);
395}
396
397/*
398 * Process an ioctl request.
399 */
400static int
401lpioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
402{
403	struct lp_data *sc = ifp->if_softc;
404	device_t dev = sc->sc_dev;
405	device_t ppbus = device_get_parent(dev);
406	struct ifaddr *ifa = (struct ifaddr *)data;
407	struct ifreq *ifr = (struct ifreq *)data;
408	u_char *ptr;
409	int error;
410
411	switch (cmd) {
412	case SIOCSIFDSTADDR:
413	case SIOCAIFADDR:
414	case SIOCSIFADDR:
415		if (ifa->ifa_addr->sa_family != AF_INET)
416			return (EAFNOSUPPORT);
417
418		ifp->if_flags |= IFF_UP;
419		/* FALLTHROUGH */
420	case SIOCSIFFLAGS:
421		error = 0;
422		ppb_lock(ppbus);
423		if ((!(ifp->if_flags & IFF_UP)) &&
424		    (ifp->if_drv_flags & IFF_DRV_RUNNING))
425			lpstop(sc);
426		else if (((ifp->if_flags & IFF_UP)) &&
427		    (!(ifp->if_drv_flags & IFF_DRV_RUNNING)))
428			error = lpinit_locked(ifp);
429		ppb_unlock(ppbus);
430		return (error);
431
432	case SIOCSIFMTU:
433		ppb_lock(ppbus);
434		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
435			ptr = malloc(ifr->ifr_mtu + MLPIPHDRLEN, M_DEVBUF,
436			    M_NOWAIT);
437			if (ptr == NULL) {
438				ppb_unlock(ppbus);
439				return (ENOBUFS);
440			}
441			if (sc->sc_ifbuf)
442				free(sc->sc_ifbuf, M_DEVBUF);
443			sc->sc_ifbuf = ptr;
444		}
445		sc->sc_ifp->if_mtu = ifr->ifr_mtu;
446		ppb_unlock(ppbus);
447		break;
448
449	case SIOCGIFMTU:
450		ifr->ifr_mtu = sc->sc_ifp->if_mtu;
451		break;
452
453	case SIOCADDMULTI:
454	case SIOCDELMULTI:
455		if (ifr == 0) {
456			return (EAFNOSUPPORT);		/* XXX */
457		}
458		switch (ifr->ifr_addr.sa_family) {
459		case AF_INET:
460			break;
461		default:
462			return (EAFNOSUPPORT);
463		}
464		break;
465
466	case SIOCGIFMEDIA:
467		/*
468		 * No ifmedia support at this stage; maybe use it
469		 * in future for eg. protocol selection.
470		 */
471		return (EINVAL);
472
473	default:
474		lprintf("LP:ioctl(0x%lx)\n", cmd);
475		return (EINVAL);
476	}
477	return (0);
478}
479
480static __inline int
481clpoutbyte(u_char byte, int spin, device_t ppbus)
482{
483
484	ppb_wdtr(ppbus, ctxmitl[byte]);
485	while (ppb_rstr(ppbus) & CLPIP_SHAKE)
486		if (--spin == 0) {
487			return (1);
488		}
489	ppb_wdtr(ppbus, ctxmith[byte]);
490	while (!(ppb_rstr(ppbus) & CLPIP_SHAKE))
491		if (--spin == 0) {
492			return (1);
493		}
494	return (0);
495}
496
497static __inline int
498clpinbyte(int spin, device_t ppbus)
499{
500	u_char c, cl;
501
502	while ((ppb_rstr(ppbus) & CLPIP_SHAKE))
503		if (!--spin) {
504			return (-1);
505		}
506	cl = ppb_rstr(ppbus);
507	ppb_wdtr(ppbus, 0x10);
508
509	while (!(ppb_rstr(ppbus) & CLPIP_SHAKE))
510		if (!--spin) {
511			return (-1);
512		}
513	c = ppb_rstr(ppbus);
514	ppb_wdtr(ppbus, 0x00);
515
516	return (ctrecvl[cl] | ctrecvh[c]);
517}
518
519static void
520lptap(struct ifnet *ifp, struct mbuf *m)
521{
522	u_int32_t af = AF_INET;
523
524	bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m);
525}
526
527static void
528lp_intr(void *arg)
529{
530	struct lp_data *sc = arg;
531	device_t ppbus = device_get_parent(sc->sc_dev);
532	int len, j;
533	u_char *bp;
534	u_char c, cl;
535	struct mbuf *top;
536
537	ppb_assert_locked(ppbus);
538	if (sc->sc_ifp->if_flags & IFF_LINK0) {
539
540		/* Ack. the request */
541		ppb_wdtr(ppbus, 0x01);
542
543		/* Get the packet length */
544		j = clpinbyte(LPMAXSPIN2, ppbus);
545		if (j == -1)
546			goto err;
547		len = j;
548		j = clpinbyte(LPMAXSPIN2, ppbus);
549		if (j == -1)
550			goto err;
551		len = len + (j << 8);
552		if (len > sc->sc_ifp->if_mtu + MLPIPHDRLEN)
553			goto err;
554
555		bp = sc->sc_ifbuf;
556
557		while (len--) {
558			j = clpinbyte(LPMAXSPIN2, ppbus);
559			if (j == -1) {
560				goto err;
561			}
562			*bp++ = j;
563		}
564
565		/* Get and ignore checksum */
566		j = clpinbyte(LPMAXSPIN2, ppbus);
567		if (j == -1) {
568			goto err;
569		}
570
571		len = bp - sc->sc_ifbuf;
572		if (len <= CLPIPHDRLEN)
573			goto err;
574
575		sc->sc_iferrs = 0;
576
577		len -= CLPIPHDRLEN;
578		sc->sc_ifp->if_ipackets++;
579		sc->sc_ifp->if_ibytes += len;
580		top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, sc->sc_ifp,
581		    0);
582		if (top) {
583			ppb_unlock(ppbus);
584			if (bpf_peers_present(sc->sc_ifp->if_bpf))
585				lptap(sc->sc_ifp, top);
586
587			/* mbuf is free'd on failure. */
588			netisr_queue(NETISR_IP, top);
589			ppb_lock(ppbus);
590		}
591		return;
592	}
593	while ((ppb_rstr(ppbus) & LPIP_SHAKE)) {
594		len = sc->sc_ifp->if_mtu + LPIPHDRLEN;
595		bp  = sc->sc_ifbuf;
596		while (len--) {
597
598			cl = ppb_rstr(ppbus);
599			ppb_wdtr(ppbus, 8);
600
601			j = LPMAXSPIN2;
602			while ((ppb_rstr(ppbus) & LPIP_SHAKE))
603				if (!--j)
604					goto err;
605
606			c = ppb_rstr(ppbus);
607			ppb_wdtr(ppbus, 0);
608
609			*bp++= trecvh[cl] | trecvl[c];
610
611			j = LPMAXSPIN2;
612			while (!((cl = ppb_rstr(ppbus)) & LPIP_SHAKE)) {
613				if (cl != c &&
614				    (((cl = ppb_rstr(ppbus)) ^ 0xb8) & 0xf8) ==
615				    (c & 0xf8))
616					goto end;
617				if (!--j)
618					goto err;
619			}
620		}
621
622	end:
623		len = bp - sc->sc_ifbuf;
624		if (len <= LPIPHDRLEN)
625			goto err;
626
627		sc->sc_iferrs = 0;
628
629		len -= LPIPHDRLEN;
630		sc->sc_ifp->if_ipackets++;
631		sc->sc_ifp->if_ibytes += len;
632		top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, sc->sc_ifp,
633		    0);
634		if (top) {
635			ppb_unlock(ppbus);
636			if (bpf_peers_present(sc->sc_ifp->if_bpf))
637				lptap(sc->sc_ifp, top);
638
639			/* mbuf is free'd on failure. */
640			netisr_queue(NETISR_IP, top);
641			ppb_lock(ppbus);
642		}
643	}
644	return;
645
646err:
647	ppb_wdtr(ppbus, 0);
648	lprintf("R");
649	sc->sc_ifp->if_ierrors++;
650	sc->sc_iferrs++;
651
652	/*
653	 * We are not able to send receive anything for now,
654	 * so stop wasting our time
655	 */
656	if (sc->sc_iferrs > LPMAXERRS) {
657		if_printf(sc->sc_ifp, "Too many errors, Going off-line.\n");
658		ppb_wctr(ppbus, 0x00);
659		sc->sc_ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
660		sc->sc_iferrs = 0;
661	}
662}
663
664static __inline int
665lpoutbyte(u_char byte, int spin, device_t ppbus)
666{
667
668	ppb_wdtr(ppbus, txmith[byte]);
669	while (!(ppb_rstr(ppbus) & LPIP_SHAKE))
670		if (--spin == 0)
671			return (1);
672	ppb_wdtr(ppbus, txmitl[byte]);
673	while (ppb_rstr(ppbus) & LPIP_SHAKE)
674		if (--spin == 0)
675			return (1);
676	return (0);
677}
678
679static int
680lpoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
681    struct rtentry *rt)
682{
683	struct lp_data *sc = ifp->if_softc;
684	device_t dev = sc->sc_dev;
685	device_t ppbus = device_get_parent(dev);
686	int err;
687	struct mbuf *mm;
688	u_char *cp = "\0\0";
689	u_char chksum = 0;
690	int count = 0;
691	int i, len, spin;
692
693	/* We need a sensible value if we abort */
694	cp++;
695	ppb_lock(ppbus);
696	ifp->if_drv_flags |= IFF_DRV_OACTIVE;
697
698	err = 1;		/* assume we're aborting because of an error */
699
700	/* Suspend (on laptops) or receive-errors might have taken us offline */
701	ppb_wctr(ppbus, IRQENABLE);
702
703	if (ifp->if_flags & IFF_LINK0) {
704		if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) {
705			lprintf("&");
706			lp_intr(sc);
707		}
708
709		/* Alert other end to pending packet */
710		spin = LPMAXSPIN1;
711		ppb_wdtr(ppbus, 0x08);
712		while ((ppb_rstr(ppbus) & 0x08) == 0)
713			if (--spin == 0) {
714				goto nend;
715			}
716
717		/* Calculate length of packet, then send that */
718
719		count += 14;		/* Ethernet header len */
720
721		mm = m;
722		for (mm = m; mm; mm = mm->m_next) {
723			count += mm->m_len;
724		}
725		if (clpoutbyte(count & 0xFF, LPMAXSPIN1, ppbus))
726			goto nend;
727		if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, ppbus))
728			goto nend;
729
730		/* Send dummy ethernet header */
731		for (i = 0; i < 12; i++) {
732			if (clpoutbyte(i, LPMAXSPIN1, ppbus))
733				goto nend;
734			chksum += i;
735		}
736
737		if (clpoutbyte(0x08, LPMAXSPIN1, ppbus))
738			goto nend;
739		if (clpoutbyte(0x00, LPMAXSPIN1, ppbus))
740			goto nend;
741		chksum += 0x08 + 0x00;		/* Add into checksum */
742
743		mm = m;
744		do {
745			cp = mtod(mm, u_char *);
746			len = mm->m_len;
747			while (len--) {
748				chksum += *cp;
749				if (clpoutbyte(*cp++, LPMAXSPIN2, ppbus))
750					goto nend;
751			}
752		} while ((mm = mm->m_next));
753
754		/* Send checksum */
755		if (clpoutbyte(chksum, LPMAXSPIN2, ppbus))
756			goto nend;
757
758		/* Go quiescent */
759		ppb_wdtr(ppbus, 0);
760
761		err = 0;			/* No errors */
762
763	nend:
764		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
765		if (err)  {			/* if we didn't timeout... */
766			ifp->if_oerrors++;
767			lprintf("X");
768		} else {
769			ifp->if_opackets++;
770			ifp->if_obytes += m->m_pkthdr.len;
771			if (bpf_peers_present(ifp->if_bpf))
772				lptap(ifp, m);
773		}
774
775		m_freem(m);
776
777		if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) {
778			lprintf("^");
779			lp_intr(sc);
780		}
781		ppb_unlock(ppbus);
782		return (0);
783	}
784
785	if (ppb_rstr(ppbus) & LPIP_SHAKE) {
786		lprintf("&");
787		lp_intr(sc);
788	}
789
790	if (lpoutbyte(0x08, LPMAXSPIN1, ppbus))
791		goto end;
792	if (lpoutbyte(0x00, LPMAXSPIN2, ppbus))
793		goto end;
794
795	mm = m;
796	do {
797		cp = mtod(mm, u_char *);
798		len = mm->m_len;
799		while (len--)
800			if (lpoutbyte(*cp++, LPMAXSPIN2, ppbus))
801				goto end;
802	} while ((mm = mm->m_next));
803
804	err = 0;			/* no errors were encountered */
805
806end:
807	--cp;
808	ppb_wdtr(ppbus, txmitl[*cp] ^ 0x17);
809
810	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
811	if (err)  {			/* if we didn't timeout... */
812		ifp->if_oerrors++;
813		lprintf("X");
814	} else {
815		ifp->if_opackets++;
816		ifp->if_obytes += m->m_pkthdr.len;
817		if (bpf_peers_present(ifp->if_bpf))
818			lptap(ifp, m);
819	}
820
821	m_freem(m);
822
823	if (ppb_rstr(ppbus) & LPIP_SHAKE) {
824		lprintf("^");
825		lp_intr(sc);
826	}
827
828	ppb_unlock(ppbus);
829	return (0);
830}
831
832static device_method_t lp_methods[] = {
833  	/* device interface */
834	DEVMETHOD(device_identify,	lp_identify),
835	DEVMETHOD(device_probe,		lp_probe),
836	DEVMETHOD(device_attach,	lp_attach),
837	DEVMETHOD(device_detach,	lp_detach),
838
839	{ 0, 0 }
840};
841
842static driver_t lp_driver = {
843	"plip",
844	lp_methods,
845	sizeof(struct lp_data),
846};
847
848DRIVER_MODULE(plip, ppbus, lp_driver, lp_devclass, lp_module_handler, 0);
849MODULE_DEPEND(plip, ppbus, 1, 1, 1);
850