if_plip.c revision 256281
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: stable/10/sys/dev/ppbus/if_plip.c 255471 2013-09-11 09:19:44Z glebius $");
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#include <net/route.h>
103
104#include <netinet/in.h>
105#include <netinet/in_var.h>
106
107#include <net/bpf.h>
108
109#include <dev/ppbus/ppbconf.h>
110#include "ppbus_if.h"
111#include <dev/ppbus/ppbio.h>
112
113#ifndef LPMTU			/* MTU for the lp# interfaces */
114#define	LPMTU		1500
115#endif
116
117#ifndef LPMAXSPIN1		/* DELAY factor for the lp# interfaces */
118#define	LPMAXSPIN1	8000   /* Spinning for remote intr to happen */
119#endif
120
121#ifndef LPMAXSPIN2		/* DELAY factor for the lp# interfaces */
122#define	LPMAXSPIN2	500	/* Spinning for remote handshake to happen */
123#endif
124
125#ifndef LPMAXERRS		/* Max errors before !RUNNING */
126#define	LPMAXERRS	100
127#endif
128
129#define	CLPIPHDRLEN	14	/* We send dummy ethernet addresses (two) + packet type in front of packet */
130#define	CLPIP_SHAKE	0x80	/* This bit toggles between nibble reception */
131#define	MLPIPHDRLEN	CLPIPHDRLEN
132
133#define	LPIPHDRLEN	2	/* We send 0x08, 0x00 in front of packet */
134#define	LPIP_SHAKE	0x40	/* This bit toggles between nibble reception */
135#if !defined(MLPIPHDRLEN) || LPIPHDRLEN > MLPIPHDRLEN
136#define	MLPIPHDRLEN	LPIPHDRLEN
137#endif
138
139#define	LPIPTBLSIZE	256	/* Size of octet translation table */
140
141#define	lprintf		if (lptflag) printf
142
143#ifdef PLIP_DEBUG
144static int volatile lptflag = 1;
145#else
146static int volatile lptflag = 0;
147#endif
148
149struct lp_data {
150	struct  ifnet	*sc_ifp;
151	device_t	sc_dev;
152	u_char		*sc_ifbuf;
153	int		sc_iferrs;
154
155	struct resource *res_irq;
156	void		*sc_intr_cookie;
157};
158
159static struct mtx lp_tables_lock;
160MTX_SYSINIT(lp_tables, &lp_tables_lock, "plip tables", MTX_DEF);
161
162/* Tables for the lp# interface */
163static u_char *txmith;
164#define	txmitl (txmith + (1 * LPIPTBLSIZE))
165#define	trecvh (txmith + (2 * LPIPTBLSIZE))
166#define	trecvl (txmith + (3 * LPIPTBLSIZE))
167
168static u_char *ctxmith;
169#define	ctxmitl (ctxmith + (1 * LPIPTBLSIZE))
170#define	ctrecvh (ctxmith + (2 * LPIPTBLSIZE))
171#define	ctrecvl (ctxmith + (3 * LPIPTBLSIZE))
172
173/* Functions for the lp# interface */
174static int lpinittables(void);
175static int lpioctl(struct ifnet *, u_long, caddr_t);
176static int lpoutput(struct ifnet *, struct mbuf *, const struct sockaddr *,
177       struct route *);
178static void lpstop(struct lp_data *);
179static void lp_intr(void *);
180static int lp_module_handler(module_t, int, void *);
181
182#define	DEVTOSOFTC(dev) \
183	((struct lp_data *)device_get_softc(dev))
184
185static devclass_t lp_devclass;
186
187static int
188lp_module_handler(module_t mod, int what, void *arg)
189{
190
191	switch (what) {
192	case MOD_UNLOAD:
193		mtx_lock(&lp_tables_lock);
194		if (txmith != NULL) {
195			free(txmith, M_DEVBUF);
196			txmith = NULL;
197		}
198		if (ctxmith != NULL) {
199			free(ctxmith, M_DEVBUF);
200			ctxmith = NULL;
201		}
202		mtx_unlock(&lp_tables_lock);
203		break;
204	case MOD_LOAD:
205	case MOD_QUIESCE:
206		break;
207	default:
208		return (EOPNOTSUPP);
209	}
210	return (0);
211}
212
213static void
214lp_identify(driver_t *driver, device_t parent)
215{
216	device_t dev;
217
218	dev = device_find_child(parent, "plip", -1);
219	if (!dev)
220		BUS_ADD_CHILD(parent, 0, "plip", -1);
221}
222
223static int
224lp_probe(device_t dev)
225{
226
227	device_set_desc(dev, "PLIP network interface");
228
229	return (0);
230}
231
232static int
233lp_attach(device_t dev)
234{
235	struct lp_data *lp = DEVTOSOFTC(dev);
236	struct ifnet *ifp;
237	int error, rid = 0;
238
239	lp->sc_dev = dev;
240
241	/*
242	 * Reserve the interrupt resource.  If we don't have one, the
243	 * attach fails.
244	 */
245	lp->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
246	    RF_SHAREABLE);
247	if (lp->res_irq == 0) {
248		device_printf(dev, "cannot reserve interrupt, failed.\n");
249		return (ENXIO);
250	}
251
252	ifp = lp->sc_ifp = if_alloc(IFT_PARA);
253	if (ifp == NULL) {
254		return (ENOSPC);
255	}
256
257	ifp->if_softc = lp;
258	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
259	ifp->if_mtu = LPMTU;
260	ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST;
261	ifp->if_ioctl = lpioctl;
262	ifp->if_output = lpoutput;
263	ifp->if_hdrlen = 0;
264	ifp->if_addrlen = 0;
265	ifp->if_snd.ifq_maxlen = ifqmaxlen;
266	if_attach(ifp);
267
268	bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
269
270	/*
271	 * Attach our interrupt handler.  It is only called while we
272	 * own the ppbus.
273	 */
274	error = bus_setup_intr(dev, lp->res_irq, INTR_TYPE_NET | INTR_MPSAFE,
275	    NULL, lp_intr, lp, &lp->sc_intr_cookie);
276	if (error) {
277		bpfdetach(ifp);
278		if_detach(ifp);
279		bus_release_resource(dev, SYS_RES_IRQ, 0, lp->res_irq);
280		device_printf(dev, "Unable to register interrupt handler\n");
281		return (error);
282	}
283
284	return (0);
285}
286
287static int
288lp_detach(device_t dev)
289{
290	struct lp_data *sc = device_get_softc(dev);
291	device_t ppbus = device_get_parent(dev);
292
293	ppb_lock(ppbus);
294	lpstop(sc);
295	ppb_unlock(ppbus);
296	bpfdetach(sc->sc_ifp);
297	if_detach(sc->sc_ifp);
298	bus_teardown_intr(dev, sc->res_irq, sc->sc_intr_cookie);
299	bus_release_resource(dev, SYS_RES_IRQ, 0, sc->res_irq);
300	return (0);
301}
302
303/*
304 * Build the translation tables for the LPIP (BSD unix) protocol.
305 * We don't want to calculate these nasties in our tight loop, so we
306 * precalculate them when we initialize.
307 */
308static int
309lpinittables(void)
310{
311	int i;
312
313	mtx_lock(&lp_tables_lock);
314	if (txmith == NULL)
315		txmith = malloc(4 * LPIPTBLSIZE, M_DEVBUF, M_NOWAIT);
316
317	if (txmith == NULL) {
318		mtx_unlock(&lp_tables_lock);
319		return (1);
320	}
321
322	if (ctxmith == NULL)
323		ctxmith = malloc(4 * LPIPTBLSIZE, M_DEVBUF, M_NOWAIT);
324
325	if (ctxmith == NULL) {
326		mtx_unlock(&lp_tables_lock);
327		return (1);
328	}
329
330	for (i = 0; i < LPIPTBLSIZE; i++) {
331		ctxmith[i] = (i & 0xF0) >> 4;
332		ctxmitl[i] = 0x10 | (i & 0x0F);
333		ctrecvh[i] = (i & 0x78) << 1;
334		ctrecvl[i] = (i & 0x78) >> 3;
335	}
336
337	for (i = 0; i < LPIPTBLSIZE; i++) {
338		txmith[i] = ((i & 0x80) >> 3) | ((i & 0x70) >> 4) | 0x08;
339		txmitl[i] = ((i & 0x08) << 1) | (i & 0x07);
340		trecvh[i] = ((~i) & 0x80) | ((i & 0x38) << 1);
341		trecvl[i] = (((~i) & 0x80) >> 4) | ((i & 0x38) >> 3);
342	}
343	mtx_unlock(&lp_tables_lock);
344
345	return (0);
346}
347
348static void
349lpstop(struct lp_data *sc)
350{
351	device_t ppbus = device_get_parent(sc->sc_dev);
352
353	ppb_assert_locked(ppbus);
354	ppb_wctr(ppbus, 0x00);
355	sc->sc_ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
356	free(sc->sc_ifbuf, M_DEVBUF);
357	sc->sc_ifbuf = NULL;
358
359	/* IFF_UP is not set, try to release the bus anyway */
360	ppb_release_bus(ppbus, sc->sc_dev);
361}
362
363static int
364lpinit_locked(struct ifnet *ifp)
365{
366	struct lp_data *sc = ifp->if_softc;
367	device_t dev = sc->sc_dev;
368	device_t ppbus = device_get_parent(dev);
369	int error;
370
371	ppb_assert_locked(ppbus);
372	error = ppb_request_bus(ppbus, dev, PPB_DONTWAIT);
373	if (error)
374		return (error);
375
376	/* Now IFF_UP means that we own the bus */
377	ppb_set_mode(ppbus, PPB_COMPATIBLE);
378
379	if (lpinittables()) {
380		ppb_release_bus(ppbus, dev);
381		return (ENOBUFS);
382	}
383
384	sc->sc_ifbuf = malloc(sc->sc_ifp->if_mtu + MLPIPHDRLEN,
385	    M_DEVBUF, M_NOWAIT);
386	if (sc->sc_ifbuf == NULL) {
387		ppb_release_bus(ppbus, dev);
388		return (ENOBUFS);
389	}
390
391	ppb_wctr(ppbus, IRQENABLE);
392
393	ifp->if_drv_flags |= IFF_DRV_RUNNING;
394	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
395	return (0);
396}
397
398/*
399 * Process an ioctl request.
400 */
401static int
402lpioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
403{
404	struct lp_data *sc = ifp->if_softc;
405	device_t dev = sc->sc_dev;
406	device_t ppbus = device_get_parent(dev);
407	struct ifaddr *ifa = (struct ifaddr *)data;
408	struct ifreq *ifr = (struct ifreq *)data;
409	u_char *ptr;
410	int error;
411
412	switch (cmd) {
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			M_SETFIB(top, sc->sc_ifp->if_fib);
588
589			/* mbuf is free'd on failure. */
590			netisr_queue(NETISR_IP, top);
591			ppb_lock(ppbus);
592		}
593		return;
594	}
595	while ((ppb_rstr(ppbus) & LPIP_SHAKE)) {
596		len = sc->sc_ifp->if_mtu + LPIPHDRLEN;
597		bp  = sc->sc_ifbuf;
598		while (len--) {
599
600			cl = ppb_rstr(ppbus);
601			ppb_wdtr(ppbus, 8);
602
603			j = LPMAXSPIN2;
604			while ((ppb_rstr(ppbus) & LPIP_SHAKE))
605				if (!--j)
606					goto err;
607
608			c = ppb_rstr(ppbus);
609			ppb_wdtr(ppbus, 0);
610
611			*bp++= trecvh[cl] | trecvl[c];
612
613			j = LPMAXSPIN2;
614			while (!((cl = ppb_rstr(ppbus)) & LPIP_SHAKE)) {
615				if (cl != c &&
616				    (((cl = ppb_rstr(ppbus)) ^ 0xb8) & 0xf8) ==
617				    (c & 0xf8))
618					goto end;
619				if (!--j)
620					goto err;
621			}
622		}
623
624	end:
625		len = bp - sc->sc_ifbuf;
626		if (len <= LPIPHDRLEN)
627			goto err;
628
629		sc->sc_iferrs = 0;
630
631		len -= LPIPHDRLEN;
632		sc->sc_ifp->if_ipackets++;
633		sc->sc_ifp->if_ibytes += len;
634		top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, sc->sc_ifp,
635		    0);
636		if (top) {
637			ppb_unlock(ppbus);
638			if (bpf_peers_present(sc->sc_ifp->if_bpf))
639				lptap(sc->sc_ifp, top);
640
641			M_SETFIB(top, sc->sc_ifp->if_fib);
642
643			/* mbuf is free'd on failure. */
644			netisr_queue(NETISR_IP, top);
645			ppb_lock(ppbus);
646		}
647	}
648	return;
649
650err:
651	ppb_wdtr(ppbus, 0);
652	lprintf("R");
653	sc->sc_ifp->if_ierrors++;
654	sc->sc_iferrs++;
655
656	/*
657	 * We are not able to send receive anything for now,
658	 * so stop wasting our time
659	 */
660	if (sc->sc_iferrs > LPMAXERRS) {
661		if_printf(sc->sc_ifp, "Too many errors, Going off-line.\n");
662		ppb_wctr(ppbus, 0x00);
663		sc->sc_ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
664		sc->sc_iferrs = 0;
665	}
666}
667
668static __inline int
669lpoutbyte(u_char byte, int spin, device_t ppbus)
670{
671
672	ppb_wdtr(ppbus, txmith[byte]);
673	while (!(ppb_rstr(ppbus) & LPIP_SHAKE))
674		if (--spin == 0)
675			return (1);
676	ppb_wdtr(ppbus, txmitl[byte]);
677	while (ppb_rstr(ppbus) & LPIP_SHAKE)
678		if (--spin == 0)
679			return (1);
680	return (0);
681}
682
683static int
684lpoutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
685    struct route *ro)
686{
687	struct lp_data *sc = ifp->if_softc;
688	device_t dev = sc->sc_dev;
689	device_t ppbus = device_get_parent(dev);
690	int err;
691	struct mbuf *mm;
692	u_char *cp = "\0\0";
693	u_char chksum = 0;
694	int count = 0;
695	int i, len, spin;
696
697	/* We need a sensible value if we abort */
698	cp++;
699	ppb_lock(ppbus);
700	ifp->if_drv_flags |= IFF_DRV_OACTIVE;
701
702	err = 1;		/* assume we're aborting because of an error */
703
704	/* Suspend (on laptops) or receive-errors might have taken us offline */
705	ppb_wctr(ppbus, IRQENABLE);
706
707	if (ifp->if_flags & IFF_LINK0) {
708		if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) {
709			lprintf("&");
710			lp_intr(sc);
711		}
712
713		/* Alert other end to pending packet */
714		spin = LPMAXSPIN1;
715		ppb_wdtr(ppbus, 0x08);
716		while ((ppb_rstr(ppbus) & 0x08) == 0)
717			if (--spin == 0) {
718				goto nend;
719			}
720
721		/* Calculate length of packet, then send that */
722
723		count += 14;		/* Ethernet header len */
724
725		mm = m;
726		for (mm = m; mm; mm = mm->m_next) {
727			count += mm->m_len;
728		}
729		if (clpoutbyte(count & 0xFF, LPMAXSPIN1, ppbus))
730			goto nend;
731		if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, ppbus))
732			goto nend;
733
734		/* Send dummy ethernet header */
735		for (i = 0; i < 12; i++) {
736			if (clpoutbyte(i, LPMAXSPIN1, ppbus))
737				goto nend;
738			chksum += i;
739		}
740
741		if (clpoutbyte(0x08, LPMAXSPIN1, ppbus))
742			goto nend;
743		if (clpoutbyte(0x00, LPMAXSPIN1, ppbus))
744			goto nend;
745		chksum += 0x08 + 0x00;		/* Add into checksum */
746
747		mm = m;
748		do {
749			cp = mtod(mm, u_char *);
750			len = mm->m_len;
751			while (len--) {
752				chksum += *cp;
753				if (clpoutbyte(*cp++, LPMAXSPIN2, ppbus))
754					goto nend;
755			}
756		} while ((mm = mm->m_next));
757
758		/* Send checksum */
759		if (clpoutbyte(chksum, LPMAXSPIN2, ppbus))
760			goto nend;
761
762		/* Go quiescent */
763		ppb_wdtr(ppbus, 0);
764
765		err = 0;			/* No errors */
766
767	nend:
768		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
769		if (err)  {			/* if we didn't timeout... */
770			ifp->if_oerrors++;
771			lprintf("X");
772		} else {
773			ifp->if_opackets++;
774			ifp->if_obytes += m->m_pkthdr.len;
775			if (bpf_peers_present(ifp->if_bpf))
776				lptap(ifp, m);
777		}
778
779		m_freem(m);
780
781		if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) {
782			lprintf("^");
783			lp_intr(sc);
784		}
785		ppb_unlock(ppbus);
786		return (0);
787	}
788
789	if (ppb_rstr(ppbus) & LPIP_SHAKE) {
790		lprintf("&");
791		lp_intr(sc);
792	}
793
794	if (lpoutbyte(0x08, LPMAXSPIN1, ppbus))
795		goto end;
796	if (lpoutbyte(0x00, LPMAXSPIN2, ppbus))
797		goto end;
798
799	mm = m;
800	do {
801		cp = mtod(mm, u_char *);
802		len = mm->m_len;
803		while (len--)
804			if (lpoutbyte(*cp++, LPMAXSPIN2, ppbus))
805				goto end;
806	} while ((mm = mm->m_next));
807
808	err = 0;			/* no errors were encountered */
809
810end:
811	--cp;
812	ppb_wdtr(ppbus, txmitl[*cp] ^ 0x17);
813
814	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
815	if (err)  {			/* if we didn't timeout... */
816		ifp->if_oerrors++;
817		lprintf("X");
818	} else {
819		ifp->if_opackets++;
820		ifp->if_obytes += m->m_pkthdr.len;
821		if (bpf_peers_present(ifp->if_bpf))
822			lptap(ifp, m);
823	}
824
825	m_freem(m);
826
827	if (ppb_rstr(ppbus) & LPIP_SHAKE) {
828		lprintf("^");
829		lp_intr(sc);
830	}
831
832	ppb_unlock(ppbus);
833	return (0);
834}
835
836static device_method_t lp_methods[] = {
837  	/* device interface */
838	DEVMETHOD(device_identify,	lp_identify),
839	DEVMETHOD(device_probe,		lp_probe),
840	DEVMETHOD(device_attach,	lp_attach),
841	DEVMETHOD(device_detach,	lp_detach),
842
843	{ 0, 0 }
844};
845
846static driver_t lp_driver = {
847	"plip",
848	lp_methods,
849	sizeof(struct lp_data),
850};
851
852DRIVER_MODULE(plip, ppbus, lp_driver, lp_devclass, lp_module_handler, 0);
853MODULE_DEPEND(plip, ppbus, 1, 1, 1);
854