1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 1997 Poul-Henning Kamp
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 *	From Id: lpt.c,v 1.55.2.1 1996/11/12 09:08:38 phk Exp
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD$");
33
34/*
35 * Parallel port TCP/IP interfaces added.  I looked at the driver from
36 * MACH but this is a complete rewrite, and btw. incompatible, and it
37 * should perform better too.  I have never run the MACH driver though.
38 *
39 * This driver sends two bytes (0x08, 0x00) in front of each packet,
40 * to allow us to distinguish another format later.
41 *
42 * Now added a Linux/Crynwr compatibility mode which is enabled using
43 * IF_LINK0 - Tim Wilkinson.
44 *
45 * TODO:
46 *    Make HDLC/PPP mode, use IF_LLC1 to enable.
47 *
48 * Connect the two computers using a Laplink parallel cable to use this
49 * feature:
50 *
51 *      +----------------------------------------+
52 * 	|A-name	A-End	B-End	Descr.	Port/Bit |
53 *      +----------------------------------------+
54 *	|DATA0	2	15	Data	0/0x01   |
55 *	|-ERROR	15	2	   	1/0x08   |
56 *      +----------------------------------------+
57 *	|DATA1	3	13	Data	0/0x02	 |
58 *	|+SLCT	13	3	   	1/0x10   |
59 *      +----------------------------------------+
60 *	|DATA2	4	12	Data	0/0x04   |
61 *	|+PE	12	4	   	1/0x20   |
62 *      +----------------------------------------+
63 *	|DATA3	5	10	Strobe	0/0x08   |
64 *	|-ACK	10	5	   	1/0x40   |
65 *      +----------------------------------------+
66 *	|DATA4	6	11	Data	0/0x10   |
67 *	|BUSY	11	6	   	1/~0x80  |
68 *      +----------------------------------------+
69 *	|GND	18-25	18-25	GND	-        |
70 *      +----------------------------------------+
71 *
72 * Expect transfer-rates up to 75 kbyte/sec.
73 *
74 * If GCC could correctly grok
75 *	register int port asm("edx")
76 * the code would be cleaner
77 *
78 * Poul-Henning Kamp <phk@freebsd.org>
79 */
80
81/*
82 * Update for ppbus, PLIP support only - Nicolas Souchu
83 */
84
85#include "opt_plip.h"
86
87#include <sys/param.h>
88#include <sys/systm.h>
89#include <sys/module.h>
90#include <sys/bus.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/bus.h>
98#include <machine/resource.h>
99#include <sys/rman.h>
100
101#include <net/if.h>
102#include <net/if_var.h>
103#include <net/if_types.h>
104#include <net/netisr.h>
105#include <net/route.h>
106
107#include <netinet/in.h>
108#include <netinet/in_var.h>
109
110#include <net/bpf.h>
111
112#include <dev/ppbus/ppbconf.h>
113#include "ppbus_if.h"
114#include <dev/ppbus/ppbio.h>
115
116#ifndef LPMTU			/* MTU for the lp# interfaces */
117#define	LPMTU		1500
118#endif
119
120#ifndef LPMAXSPIN1		/* DELAY factor for the lp# interfaces */
121#define	LPMAXSPIN1	8000   /* Spinning for remote intr to happen */
122#endif
123
124#ifndef LPMAXSPIN2		/* DELAY factor for the lp# interfaces */
125#define	LPMAXSPIN2	500	/* Spinning for remote handshake to happen */
126#endif
127
128#ifndef LPMAXERRS		/* Max errors before !RUNNING */
129#define	LPMAXERRS	100
130#endif
131
132#define	CLPIPHDRLEN	14	/* We send dummy ethernet addresses (two) + packet type in front of packet */
133#define	CLPIP_SHAKE	0x80	/* This bit toggles between nibble reception */
134#define	MLPIPHDRLEN	CLPIPHDRLEN
135
136#define	LPIPHDRLEN	2	/* We send 0x08, 0x00 in front of packet */
137#define	LPIP_SHAKE	0x40	/* This bit toggles between nibble reception */
138#if !defined(MLPIPHDRLEN) || LPIPHDRLEN > MLPIPHDRLEN
139#define	MLPIPHDRLEN	LPIPHDRLEN
140#endif
141
142#define	LPIPTBLSIZE	256	/* Size of octet translation table */
143
144#define	lprintf		if (lptflag) printf
145
146#ifdef PLIP_DEBUG
147static int volatile lptflag = 1;
148#else
149static int volatile lptflag = 0;
150#endif
151
152struct lp_data {
153	struct  ifnet	*sc_ifp;
154	device_t	sc_dev;
155	u_char		*sc_ifbuf;
156	int		sc_iferrs;
157
158	struct resource *res_irq;
159	void		*sc_intr_cookie;
160};
161
162static struct mtx lp_tables_lock;
163MTX_SYSINIT(lp_tables, &lp_tables_lock, "plip tables", MTX_DEF);
164
165/* Tables for the lp# interface */
166static u_char *txmith;
167#define	txmitl (txmith + (1 * LPIPTBLSIZE))
168#define	trecvh (txmith + (2 * LPIPTBLSIZE))
169#define	trecvl (txmith + (3 * LPIPTBLSIZE))
170
171static u_char *ctxmith;
172#define	ctxmitl (ctxmith + (1 * LPIPTBLSIZE))
173#define	ctrecvh (ctxmith + (2 * LPIPTBLSIZE))
174#define	ctrecvl (ctxmith + (3 * LPIPTBLSIZE))
175
176/* Functions for the lp# interface */
177static int lpinittables(void);
178static int lpioctl(struct ifnet *, u_long, caddr_t);
179static int lpoutput(struct ifnet *, struct mbuf *, const struct sockaddr *,
180       struct route *);
181static void lpstop(struct lp_data *);
182static void lp_intr(void *);
183static int lp_module_handler(module_t, int, void *);
184
185#define	DEVTOSOFTC(dev) \
186	((struct lp_data *)device_get_softc(dev))
187
188static devclass_t lp_devclass;
189
190static int
191lp_module_handler(module_t mod, int what, void *arg)
192{
193
194	switch (what) {
195	case MOD_UNLOAD:
196		mtx_lock(&lp_tables_lock);
197		if (txmith != NULL) {
198			free(txmith, M_DEVBUF);
199			txmith = NULL;
200		}
201		if (ctxmith != NULL) {
202			free(ctxmith, M_DEVBUF);
203			ctxmith = NULL;
204		}
205		mtx_unlock(&lp_tables_lock);
206		break;
207	case MOD_LOAD:
208	case MOD_QUIESCE:
209		break;
210	default:
211		return (EOPNOTSUPP);
212	}
213	return (0);
214}
215
216static void
217lp_identify(driver_t *driver, device_t parent)
218{
219	device_t dev;
220
221	dev = device_find_child(parent, "plip", -1);
222	if (!dev)
223		BUS_ADD_CHILD(parent, 0, "plip", -1);
224}
225
226static int
227lp_probe(device_t dev)
228{
229
230	device_set_desc(dev, "PLIP network interface");
231
232	return (0);
233}
234
235static int
236lp_attach(device_t dev)
237{
238	struct lp_data *lp = DEVTOSOFTC(dev);
239	struct ifnet *ifp;
240	int error, rid = 0;
241
242	lp->sc_dev = dev;
243
244	/*
245	 * Reserve the interrupt resource.  If we don't have one, the
246	 * attach fails.
247	 */
248	lp->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
249	    RF_SHAREABLE);
250	if (lp->res_irq == NULL) {
251		device_printf(dev, "cannot reserve interrupt, failed.\n");
252		return (ENXIO);
253	}
254
255	ifp = lp->sc_ifp = if_alloc(IFT_PARA);
256	if (ifp == NULL) {
257		return (ENOSPC);
258	}
259
260	ifp->if_softc = lp;
261	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
262	ifp->if_mtu = LPMTU;
263	ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST;
264	ifp->if_ioctl = lpioctl;
265	ifp->if_output = lpoutput;
266	ifp->if_hdrlen = 0;
267	ifp->if_addrlen = 0;
268	ifp->if_snd.ifq_maxlen = ifqmaxlen;
269	if_attach(ifp);
270
271	bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
272
273	/*
274	 * Attach our interrupt handler.  It is only called while we
275	 * own the ppbus.
276	 */
277	error = bus_setup_intr(dev, lp->res_irq, INTR_TYPE_NET | INTR_MPSAFE,
278	    NULL, lp_intr, lp, &lp->sc_intr_cookie);
279	if (error) {
280		bpfdetach(ifp);
281		if_detach(ifp);
282		bus_release_resource(dev, SYS_RES_IRQ, 0, lp->res_irq);
283		device_printf(dev, "Unable to register interrupt handler\n");
284		return (error);
285	}
286
287	return (0);
288}
289
290static int
291lp_detach(device_t dev)
292{
293	struct lp_data *sc = device_get_softc(dev);
294	device_t ppbus = device_get_parent(dev);
295
296	ppb_lock(ppbus);
297	lpstop(sc);
298	ppb_unlock(ppbus);
299	bpfdetach(sc->sc_ifp);
300	if_detach(sc->sc_ifp);
301	bus_teardown_intr(dev, sc->res_irq, sc->sc_intr_cookie);
302	bus_release_resource(dev, SYS_RES_IRQ, 0, sc->res_irq);
303	return (0);
304}
305
306/*
307 * Build the translation tables for the LPIP (BSD unix) protocol.
308 * We don't want to calculate these nasties in our tight loop, so we
309 * precalculate them when we initialize.
310 */
311static int
312lpinittables(void)
313{
314	int i;
315
316	mtx_lock(&lp_tables_lock);
317	if (txmith == NULL)
318		txmith = malloc(4 * LPIPTBLSIZE, M_DEVBUF, M_NOWAIT);
319
320	if (txmith == NULL) {
321		mtx_unlock(&lp_tables_lock);
322		return (1);
323	}
324
325	if (ctxmith == NULL)
326		ctxmith = malloc(4 * LPIPTBLSIZE, M_DEVBUF, M_NOWAIT);
327
328	if (ctxmith == NULL) {
329		mtx_unlock(&lp_tables_lock);
330		return (1);
331	}
332
333	for (i = 0; i < LPIPTBLSIZE; i++) {
334		ctxmith[i] = (i & 0xF0) >> 4;
335		ctxmitl[i] = 0x10 | (i & 0x0F);
336		ctrecvh[i] = (i & 0x78) << 1;
337		ctrecvl[i] = (i & 0x78) >> 3;
338	}
339
340	for (i = 0; i < LPIPTBLSIZE; i++) {
341		txmith[i] = ((i & 0x80) >> 3) | ((i & 0x70) >> 4) | 0x08;
342		txmitl[i] = ((i & 0x08) << 1) | (i & 0x07);
343		trecvh[i] = ((~i) & 0x80) | ((i & 0x38) << 1);
344		trecvl[i] = (((~i) & 0x80) >> 4) | ((i & 0x38) >> 3);
345	}
346	mtx_unlock(&lp_tables_lock);
347
348	return (0);
349}
350
351static void
352lpstop(struct lp_data *sc)
353{
354	device_t ppbus = device_get_parent(sc->sc_dev);
355
356	ppb_assert_locked(ppbus);
357	ppb_wctr(ppbus, 0x00);
358	sc->sc_ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
359	free(sc->sc_ifbuf, M_DEVBUF);
360	sc->sc_ifbuf = NULL;
361
362	/* IFF_UP is not set, try to release the bus anyway */
363	ppb_release_bus(ppbus, sc->sc_dev);
364}
365
366static int
367lpinit_locked(struct ifnet *ifp)
368{
369	struct lp_data *sc = ifp->if_softc;
370	device_t dev = sc->sc_dev;
371	device_t ppbus = device_get_parent(dev);
372	int error;
373
374	ppb_assert_locked(ppbus);
375	error = ppb_request_bus(ppbus, dev, PPB_DONTWAIT);
376	if (error)
377		return (error);
378
379	/* Now IFF_UP means that we own the bus */
380	ppb_set_mode(ppbus, PPB_COMPATIBLE);
381
382	if (lpinittables()) {
383		ppb_release_bus(ppbus, dev);
384		return (ENOBUFS);
385	}
386
387	sc->sc_ifbuf = malloc(sc->sc_ifp->if_mtu + MLPIPHDRLEN,
388	    M_DEVBUF, M_NOWAIT);
389	if (sc->sc_ifbuf == NULL) {
390		ppb_release_bus(ppbus, dev);
391		return (ENOBUFS);
392	}
393
394	ppb_wctr(ppbus, IRQENABLE);
395
396	ifp->if_drv_flags |= IFF_DRV_RUNNING;
397	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
398	return (0);
399}
400
401/*
402 * Process an ioctl request.
403 */
404static int
405lpioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
406{
407	struct lp_data *sc = ifp->if_softc;
408	device_t dev = sc->sc_dev;
409	device_t ppbus = device_get_parent(dev);
410	struct ifaddr *ifa = (struct ifaddr *)data;
411	struct ifreq *ifr = (struct ifreq *)data;
412	u_char *ptr;
413	int error;
414
415	switch (cmd) {
416	case SIOCAIFADDR:
417	case SIOCSIFADDR:
418		if (ifa->ifa_addr->sa_family != AF_INET)
419			return (EAFNOSUPPORT);
420
421		ifp->if_flags |= IFF_UP;
422		/* FALLTHROUGH */
423	case SIOCSIFFLAGS:
424		error = 0;
425		ppb_lock(ppbus);
426		if ((!(ifp->if_flags & IFF_UP)) &&
427		    (ifp->if_drv_flags & IFF_DRV_RUNNING))
428			lpstop(sc);
429		else if (((ifp->if_flags & IFF_UP)) &&
430		    (!(ifp->if_drv_flags & IFF_DRV_RUNNING)))
431			error = lpinit_locked(ifp);
432		ppb_unlock(ppbus);
433		return (error);
434
435	case SIOCSIFMTU:
436		ppb_lock(ppbus);
437		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
438			ptr = malloc(ifr->ifr_mtu + MLPIPHDRLEN, M_DEVBUF,
439			    M_NOWAIT);
440			if (ptr == NULL) {
441				ppb_unlock(ppbus);
442				return (ENOBUFS);
443			}
444			if (sc->sc_ifbuf)
445				free(sc->sc_ifbuf, M_DEVBUF);
446			sc->sc_ifbuf = ptr;
447		}
448		sc->sc_ifp->if_mtu = ifr->ifr_mtu;
449		ppb_unlock(ppbus);
450		break;
451
452	case SIOCGIFMTU:
453		ifr->ifr_mtu = sc->sc_ifp->if_mtu;
454		break;
455
456	case SIOCADDMULTI:
457	case SIOCDELMULTI:
458		if (ifr == NULL) {
459			return (EAFNOSUPPORT);		/* XXX */
460		}
461		switch (ifr->ifr_addr.sa_family) {
462		case AF_INET:
463			break;
464		default:
465			return (EAFNOSUPPORT);
466		}
467		break;
468
469	case SIOCGIFMEDIA:
470		/*
471		 * No ifmedia support at this stage; maybe use it
472		 * in future for eg. protocol selection.
473		 */
474		return (EINVAL);
475
476	default:
477		lprintf("LP:ioctl(0x%lx)\n", cmd);
478		return (EINVAL);
479	}
480	return (0);
481}
482
483static __inline int
484clpoutbyte(u_char byte, int spin, device_t ppbus)
485{
486
487	ppb_wdtr(ppbus, ctxmitl[byte]);
488	while (ppb_rstr(ppbus) & CLPIP_SHAKE)
489		if (--spin == 0) {
490			return (1);
491		}
492	ppb_wdtr(ppbus, ctxmith[byte]);
493	while (!(ppb_rstr(ppbus) & CLPIP_SHAKE))
494		if (--spin == 0) {
495			return (1);
496		}
497	return (0);
498}
499
500static __inline int
501clpinbyte(int spin, device_t ppbus)
502{
503	u_char c, cl;
504
505	while ((ppb_rstr(ppbus) & CLPIP_SHAKE))
506		if (!--spin) {
507			return (-1);
508		}
509	cl = ppb_rstr(ppbus);
510	ppb_wdtr(ppbus, 0x10);
511
512	while (!(ppb_rstr(ppbus) & CLPIP_SHAKE))
513		if (!--spin) {
514			return (-1);
515		}
516	c = ppb_rstr(ppbus);
517	ppb_wdtr(ppbus, 0x00);
518
519	return (ctrecvl[cl] | ctrecvh[c]);
520}
521
522static void
523lptap(struct ifnet *ifp, struct mbuf *m)
524{
525	u_int32_t af = AF_INET;
526
527	bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m);
528}
529
530static void
531lp_intr(void *arg)
532{
533	struct lp_data *sc = arg;
534	device_t ppbus = device_get_parent(sc->sc_dev);
535	int len, j;
536	u_char *bp;
537	u_char c, cl;
538	struct mbuf *top;
539
540	ppb_assert_locked(ppbus);
541	if (sc->sc_ifp->if_flags & IFF_LINK0) {
542		/* Ack. the request */
543		ppb_wdtr(ppbus, 0x01);
544
545		/* Get the packet length */
546		j = clpinbyte(LPMAXSPIN2, ppbus);
547		if (j == -1)
548			goto err;
549		len = j;
550		j = clpinbyte(LPMAXSPIN2, ppbus);
551		if (j == -1)
552			goto err;
553		len = len + (j << 8);
554		if (len > sc->sc_ifp->if_mtu + MLPIPHDRLEN)
555			goto err;
556
557		bp = sc->sc_ifbuf;
558
559		while (len--) {
560			j = clpinbyte(LPMAXSPIN2, ppbus);
561			if (j == -1) {
562				goto err;
563			}
564			*bp++ = j;
565		}
566
567		/* Get and ignore checksum */
568		j = clpinbyte(LPMAXSPIN2, ppbus);
569		if (j == -1) {
570			goto err;
571		}
572
573		len = bp - sc->sc_ifbuf;
574		if (len <= CLPIPHDRLEN)
575			goto err;
576
577		sc->sc_iferrs = 0;
578
579		len -= CLPIPHDRLEN;
580		if_inc_counter(sc->sc_ifp, IFCOUNTER_IPACKETS, 1);
581		if_inc_counter(sc->sc_ifp, IFCOUNTER_IBYTES, len);
582		top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, sc->sc_ifp,
583		    0);
584		if (top) {
585			ppb_unlock(ppbus);
586			if (bpf_peers_present(sc->sc_ifp->if_bpf))
587				lptap(sc->sc_ifp, top);
588
589			M_SETFIB(top, sc->sc_ifp->if_fib);
590
591			/* mbuf is free'd on failure. */
592			netisr_queue(NETISR_IP, top);
593			ppb_lock(ppbus);
594		}
595		return;
596	}
597	while ((ppb_rstr(ppbus) & LPIP_SHAKE)) {
598		len = sc->sc_ifp->if_mtu + LPIPHDRLEN;
599		bp  = sc->sc_ifbuf;
600		while (len--) {
601			cl = ppb_rstr(ppbus);
602			ppb_wdtr(ppbus, 8);
603
604			j = LPMAXSPIN2;
605			while ((ppb_rstr(ppbus) & LPIP_SHAKE))
606				if (!--j)
607					goto err;
608
609			c = ppb_rstr(ppbus);
610			ppb_wdtr(ppbus, 0);
611
612			*bp++= trecvh[cl] | trecvl[c];
613
614			j = LPMAXSPIN2;
615			while (!((cl = ppb_rstr(ppbus)) & LPIP_SHAKE)) {
616				if (cl != c &&
617				    (((cl = ppb_rstr(ppbus)) ^ 0xb8) & 0xf8) ==
618				    (c & 0xf8))
619					goto end;
620				if (!--j)
621					goto err;
622			}
623		}
624
625	end:
626		len = bp - sc->sc_ifbuf;
627		if (len <= LPIPHDRLEN)
628			goto err;
629
630		sc->sc_iferrs = 0;
631
632		len -= LPIPHDRLEN;
633		if_inc_counter(sc->sc_ifp, IFCOUNTER_IPACKETS, 1);
634		if_inc_counter(sc->sc_ifp, IFCOUNTER_IBYTES, len);
635		top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, sc->sc_ifp,
636		    0);
637		if (top) {
638			ppb_unlock(ppbus);
639			if (bpf_peers_present(sc->sc_ifp->if_bpf))
640				lptap(sc->sc_ifp, top);
641
642			M_SETFIB(top, sc->sc_ifp->if_fib);
643
644			/* mbuf is free'd on failure. */
645			netisr_queue(NETISR_IP, top);
646			ppb_lock(ppbus);
647		}
648	}
649	return;
650
651err:
652	ppb_wdtr(ppbus, 0);
653	lprintf("R");
654	if_inc_counter(sc->sc_ifp, IFCOUNTER_IERRORS, 1);
655	sc->sc_iferrs++;
656
657	/*
658	 * We are not able to send receive anything for now,
659	 * so stop wasting our time
660	 */
661	if (sc->sc_iferrs > LPMAXERRS) {
662		if_printf(sc->sc_ifp, "Too many errors, Going off-line.\n");
663		ppb_wctr(ppbus, 0x00);
664		sc->sc_ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
665		sc->sc_iferrs = 0;
666	}
667}
668
669static __inline int
670lpoutbyte(u_char byte, int spin, device_t ppbus)
671{
672
673	ppb_wdtr(ppbus, txmith[byte]);
674	while (!(ppb_rstr(ppbus) & LPIP_SHAKE))
675		if (--spin == 0)
676			return (1);
677	ppb_wdtr(ppbus, txmitl[byte]);
678	while (ppb_rstr(ppbus) & LPIP_SHAKE)
679		if (--spin == 0)
680			return (1);
681	return (0);
682}
683
684static int
685lpoutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
686    struct route *ro)
687{
688	struct lp_data *sc = ifp->if_softc;
689	device_t dev = sc->sc_dev;
690	device_t ppbus = device_get_parent(dev);
691	int err;
692	struct mbuf *mm;
693	u_char *cp = "\0\0";
694	u_char chksum = 0;
695	int count = 0;
696	int i, len, spin;
697
698	/* We need a sensible value if we abort */
699	cp++;
700	ppb_lock(ppbus);
701	ifp->if_drv_flags |= IFF_DRV_OACTIVE;
702
703	err = 1;		/* assume we're aborting because of an error */
704
705	/* Suspend (on laptops) or receive-errors might have taken us offline */
706	ppb_wctr(ppbus, IRQENABLE);
707
708	if (ifp->if_flags & IFF_LINK0) {
709		if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) {
710			lprintf("&");
711			lp_intr(sc);
712		}
713
714		/* Alert other end to pending packet */
715		spin = LPMAXSPIN1;
716		ppb_wdtr(ppbus, 0x08);
717		while ((ppb_rstr(ppbus) & 0x08) == 0)
718			if (--spin == 0) {
719				goto nend;
720			}
721
722		/* Calculate length of packet, then send that */
723
724		count += 14;		/* Ethernet header len */
725
726		mm = m;
727		for (mm = m; mm; mm = mm->m_next) {
728			count += mm->m_len;
729		}
730		if (clpoutbyte(count & 0xFF, LPMAXSPIN1, ppbus))
731			goto nend;
732		if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, ppbus))
733			goto nend;
734
735		/* Send dummy ethernet header */
736		for (i = 0; i < 12; i++) {
737			if (clpoutbyte(i, LPMAXSPIN1, ppbus))
738				goto nend;
739			chksum += i;
740		}
741
742		if (clpoutbyte(0x08, LPMAXSPIN1, ppbus))
743			goto nend;
744		if (clpoutbyte(0x00, LPMAXSPIN1, ppbus))
745			goto nend;
746		chksum += 0x08 + 0x00;		/* Add into checksum */
747
748		mm = m;
749		do {
750			cp = mtod(mm, u_char *);
751			len = mm->m_len;
752			while (len--) {
753				chksum += *cp;
754				if (clpoutbyte(*cp++, LPMAXSPIN2, ppbus))
755					goto nend;
756			}
757		} while ((mm = mm->m_next));
758
759		/* Send checksum */
760		if (clpoutbyte(chksum, LPMAXSPIN2, ppbus))
761			goto nend;
762
763		/* Go quiescent */
764		ppb_wdtr(ppbus, 0);
765
766		err = 0;			/* No errors */
767
768	nend:
769		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
770		if (err)  {			/* if we didn't timeout... */
771			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
772			lprintf("X");
773		} else {
774			if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
775			if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len);
776			if (bpf_peers_present(ifp->if_bpf))
777				lptap(ifp, m);
778		}
779
780		m_freem(m);
781
782		if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) {
783			lprintf("^");
784			lp_intr(sc);
785		}
786		ppb_unlock(ppbus);
787		return (0);
788	}
789
790	if (ppb_rstr(ppbus) & LPIP_SHAKE) {
791		lprintf("&");
792		lp_intr(sc);
793	}
794
795	if (lpoutbyte(0x08, LPMAXSPIN1, ppbus))
796		goto end;
797	if (lpoutbyte(0x00, LPMAXSPIN2, ppbus))
798		goto end;
799
800	mm = m;
801	do {
802		cp = mtod(mm, u_char *);
803		len = mm->m_len;
804		while (len--)
805			if (lpoutbyte(*cp++, LPMAXSPIN2, ppbus))
806				goto end;
807	} while ((mm = mm->m_next));
808
809	err = 0;			/* no errors were encountered */
810
811end:
812	--cp;
813	ppb_wdtr(ppbus, txmitl[*cp] ^ 0x17);
814
815	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
816	if (err)  {			/* if we didn't timeout... */
817		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
818		lprintf("X");
819	} else {
820		if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
821		if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len);
822		if (bpf_peers_present(ifp->if_bpf))
823			lptap(ifp, m);
824	}
825
826	m_freem(m);
827
828	if (ppb_rstr(ppbus) & LPIP_SHAKE) {
829		lprintf("^");
830		lp_intr(sc);
831	}
832
833	ppb_unlock(ppbus);
834	return (0);
835}
836
837static device_method_t lp_methods[] = {
838  	/* device interface */
839	DEVMETHOD(device_identify,	lp_identify),
840	DEVMETHOD(device_probe,		lp_probe),
841	DEVMETHOD(device_attach,	lp_attach),
842	DEVMETHOD(device_detach,	lp_detach),
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