1/* $NetBSD: if_plip.c,v 1.38 2022/09/04 15:59:08 rjs Exp $ */
2
3/*-
4 * Copyright (c) 1997 Poul-Henning Kamp
5 * Copyright (c) 2003, 2004 Gary Thorpe <gathorpe@users.sourceforge.net>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 *	From Id: lpt.c,v 1.55.2.1 1996/11/12 09:08:38 phk Exp
30 * FreeBSD: src/sys/dev/ppbus/if_plip.c,v 1.19.2.1 2000/05/24 00:20:57 n_hibma Exp
31 */
32
33#include <sys/cdefs.h>
34__KERNEL_RCSID(0, "$NetBSD: if_plip.c,v 1.38 2022/09/04 15:59:08 rjs Exp $");
35
36/*
37 * Parallel port TCP/IP interfaces added.  I looked at the driver from
38 * MACH but this is a complete rewrite, and btw. incompatible, and it
39 * should perform better too.  I have never run the MACH driver though.
40 *
41 * This driver sends two bytes (0x08, 0x00) in front of each packet,
42 * to allow us to distinguish another format later.
43 *
44 * Now added a Linux/Crynwr compatibility mode which is enabled using
45 * IF_LINK0 - Tim Wilkinson.
46 *
47 * TODO:
48 *    Make HDLC/PPP mode, use IF_LLC1 to enable.
49 *
50 * Connect the two computers using a Laplink parallel cable to use this
51 * feature:
52 *
53 *      +----------------------------------------+
54 * 	|A-name	A-End	B-End	Descr.	Port/Bit |
55 *      +----------------------------------------+
56 *	|DATA0	2	15	Data	0/0x01   |
57 *	|-ERROR	15	2	   	1/0x08   |
58 *      +----------------------------------------+
59 *	|DATA1	3	13	Data	0/0x02	 |
60 *	|+SLCT	13	3	   	1/0x10   |
61 *      +----------------------------------------+
62 *	|DATA2	4	12	Data	0/0x04   |
63 *	|+PE	12	4	   	1/0x20   |
64 *      +----------------------------------------+
65 *	|DATA3	5	10	Strobe	0/0x08   |
66 *	|-ACK	10	5	   	1/0x40   |
67 *      +----------------------------------------+
68 *	|DATA4	6	11	Data	0/0x10   |
69 *	|BUSY	11	6	   	1/~0x80  |
70 *      +----------------------------------------+
71 *	|GND	18-25	18-25	GND	-        |
72 *      +----------------------------------------+
73 *
74 * Expect transfer-rates up to 75 kbyte/sec.
75 *
76 * If GCC could correctly grok
77 *	register int port __asm("edx")
78 * the code would be cleaner
79 *
80 * Poul-Henning Kamp <phk@freebsd.org>
81 */
82
83/*
84 * Update for ppbus, PLIP support only - Nicolas Souchu
85 */
86
87#include "opt_inet.h"
88#include "opt_plip.h"
89
90#include <sys/systm.h>
91#include <sys/param.h>
92#include <sys/proc.h>
93#include <sys/types.h>
94#include <sys/device.h>
95#include <sys/ioctl.h>
96#include <sys/malloc.h>
97#include <sys/mbuf.h>
98
99#include <net/if.h>
100#include <net/if_types.h>
101
102#include <sys/time.h>
103#include <net/bpf.h>
104
105#ifdef INET
106#include <netinet/in.h>
107#include <netinet/in_systm.h>
108#include <netinet/in_var.h>
109#include <netinet/ip.h>
110#else
111#error Cannot config lp/plip without inet
112#endif
113
114#include <dev/ppbus/ppbus_base.h>
115#include <dev/ppbus/ppbus_device.h>
116#include <dev/ppbus/ppbus_io.h>
117#include <dev/ppbus/ppbus_var.h>
118
119#include <machine/types.h>
120#include <sys/intr.h>
121
122#ifndef LPMTU			/* MTU for the lp# interfaces */
123#define	LPMTU		1500
124#endif
125
126#ifndef LPMAXSPIN1		/* DELAY factor for the lp# interfaces */
127#define	LPMAXSPIN1	8000	/* Spinning for remote intr to happen */
128#endif
129
130#ifndef LPMAXSPIN2		/* DELAY factor for the lp# interfaces */
131#define	LPMAXSPIN2	500	/* Spinning for remote handshake to happen */
132#endif
133
134#ifndef LPMAXERRS		/* Max errors before !RUNNING */
135#define	LPMAXERRS	100
136#endif
137
138#ifndef LPMAXRTRY
139#define LPMAXRTRY	100	/* If channel busy, retry LPMAXRTRY
140					consecutive times */
141#endif
142
143#define CLPIPHDRLEN	14	/* We send dummy ethernet addresses (two) + packet type in front of packet */
144#define	CLPIP_SHAKE	0x80	/* This bit toggles between nibble reception */
145#define MLPIPHDRLEN	CLPIPHDRLEN
146
147#define LPIPHDRLEN	2	/* We send 0x08, 0x00 in front of packet */
148#define	LPIP_SHAKE	0x40	/* This bit toggles between nibble reception */
149#if !defined(MLPIPHDRLEN) || LPIPHDRLEN > MLPIPHDRLEN
150#define MLPIPHDRLEN	LPIPHDRLEN
151#endif
152
153#define	LPIPTBLSIZE	256	/* Size of octet translation table */
154
155#define LP_PRINTF	if (lpflag) printf
156
157#ifdef PLIP_DEBUG
158static int volatile lpflag = 1;
159#else
160static int volatile lpflag = 0;
161#endif
162
163/* Tx/Rsv tables for the lp interface */
164static u_char *txmith;
165#define txmitl (txmith+(1*LPIPTBLSIZE))
166#define trecvh (txmith+(2*LPIPTBLSIZE))
167#define trecvl (txmith+(3*LPIPTBLSIZE))
168static u_char *ctxmith;
169#define ctxmitl (ctxmith+(1*LPIPTBLSIZE))
170#define ctrecvh (ctxmith+(2*LPIPTBLSIZE))
171#define ctrecvl (ctxmith+(3*LPIPTBLSIZE))
172static uint16_t lp_count = 0;
173
174/* Autoconf functions */
175static int lp_probe(device_t, cfdata_t, void *);
176static void lp_attach(device_t, device_t, void *);
177static int lp_detach(device_t, int);
178
179/* Soft config data */
180struct lp_softc {
181	struct ppbus_device_softc ppbus_dev;
182	struct ifnet sc_if;
183	u_char *sc_ifbuf;
184	unsigned short sc_iferrs;
185	unsigned short sc_xmit_rtry;
186	u_int8_t sc_dev_ok; /* Zero means ok */
187};
188
189/* Autoconf structure */
190CFATTACH_DECL_NEW(plip, sizeof(struct lp_softc), lp_probe, lp_attach, lp_detach,
191	NULL);
192
193/* Functions for the lp interface */
194static void lpinittables(void);
195static void lpfreetables(void);
196static int lpioctl(struct ifnet *, u_long, void *);
197static int lpoutput(struct ifnet *, struct mbuf *, const struct sockaddr *,
198    const struct rtentry *);
199static void lpstart(struct ifnet *);
200static void lp_intr(void *);
201
202
203static int
204lp_probe(device_t parent, cfdata_t match, void *aux)
205{
206	struct ppbus_attach_args * args = aux;
207
208	/* Fail if ppbus is not interrupt capable */
209	if (args->capabilities & PPBUS_HAS_INTR)
210		return 1;
211
212	printf("%s(%s): not an interrupt-driven port.\n", __func__,
213		device_xname(parent));
214	return 0;
215}
216
217static void
218lp_attach(device_t parent, device_t self, void *aux)
219{
220	struct lp_softc * lp = device_private(self);
221	struct ifnet * ifp = &lp->sc_if;
222
223	lp->ppbus_dev.sc_dev = self;
224	lp->sc_dev_ok = 0;
225	lp->sc_ifbuf = NULL;
226	lp->sc_iferrs = 0;
227	lp->sc_xmit_rtry = 0;
228
229	ifp->if_softc = lp;
230	strlcpy(ifp->if_xname, device_xname(self), IFNAMSIZ);
231	ifp->if_mtu = LPMTU;
232	ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST;
233	ifp->if_ioctl = lpioctl;
234	ifp->if_output = lpoutput;
235	ifp->if_start = lpstart;
236	ifp->if_type = IFT_PARA;
237	ifp->if_hdrlen = 0;
238	ifp->if_addrlen = 0;
239	ifp->if_dlt = DLT_NULL;
240	IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
241	IFQ_SET_READY(&ifp->if_snd);
242	if_attach(ifp);
243	if_alloc_sadl(ifp);
244
245	bpf_attach(ifp, DLT_NULL, sizeof(u_int32_t));
246
247	if (lp_count++ == 0)
248		lpinittables();
249	printf("\n");
250}
251
252static int
253lp_detach(device_t self, int flags)
254{
255	int error = 0;
256	struct lp_softc * lp = device_private(self);
257	device_t ppbus = device_parent(self);
258
259	if (lp->sc_dev_ok) {
260		if (!(flags & DETACH_QUIET))
261			LP_PRINTF("%s(%s): device not properly attached! "
262				"Skipping detach....\n", __func__,
263				device_xname(self));
264		return error;
265	}
266
267	/* If interface is up, bring it down and release ppbus */
268	if (lp->sc_if.if_flags & IFF_RUNNING) {
269		ppbus_wctr(ppbus, 0x00);
270		if_detach(&lp->sc_if);
271		error = ppbus_remove_handler(ppbus, lp_intr);
272		if (error) {
273			if (!(flags & DETACH_QUIET))
274				LP_PRINTF("%s(%s): unable to remove interrupt "
275					"callback.\n", __func__,
276					device_xname(self));
277			if (!(flags & DETACH_FORCE))
278				return error;
279		}
280		error = ppbus_release_bus(ppbus, self, 0, 0);
281		if (error) {
282			if (!(flags & DETACH_QUIET))
283				LP_PRINTF("%s(%s): error releasing bus %s.\n",
284					__func__, device_xname(self),
285					device_xname(ppbus));
286			if (!(flags & DETACH_FORCE))
287				return error;
288		}
289	}
290
291	if (lp->sc_ifbuf)
292		free(lp->sc_ifbuf, M_DEVBUF);
293
294	if (--lp_count == 0)
295		lpfreetables();
296	return error;
297}
298
299/*
300 * Build the translation tables for the LPIP (BSD unix) protocol.
301 * We don't want to calculate these nasties in our tight loop, so we
302 * precalculate them when we initialize.
303 */
304static void
305lpinittables(void)
306{
307	int i;
308
309	if (!txmith)
310		txmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_WAITOK);
311
312	if (!ctxmith)
313		ctxmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_WAITOK);
314
315	for (i = 0; i < LPIPTBLSIZE; i++) {
316		ctxmith[i] = (i & 0xF0) >> 4;
317		ctxmitl[i] = 0x10 | (i & 0x0F);
318		ctrecvh[i] = (i & 0x78) << 1;
319		ctrecvl[i] = (i & 0x78) >> 3;
320	}
321
322	for (i = 0; i < LPIPTBLSIZE; i++) {
323		txmith[i] = ((i & 0x80) >> 3) | ((i & 0x70) >> 4) | 0x08;
324		txmitl[i] = ((i & 0x08) << 1) | (i & 0x07);
325		trecvh[i] = ((~i) & 0x80) | ((i & 0x38) << 1);
326		trecvl[i] = (((~i) & 0x80) >> 4) | ((i & 0x38) >> 3);
327	}
328}
329
330/* Free translation tables */
331static void
332lpfreetables(void)
333{
334	if (txmith)
335		free(txmith, M_DEVBUF);
336	if (ctxmith)
337		free(ctxmith, M_DEVBUF);
338	txmith = ctxmith = NULL;
339}
340
341
342/* Process an ioctl request. */
343static int
344lpioctl(struct ifnet *ifp, u_long cmd, void *data)
345{
346	struct lp_softc * sc = ifp->if_softc;
347	device_t dev = sc->ppbus_dev.sc_dev;
348	device_t ppbus = device_parent(dev);
349	struct ifaddr * ifa = (struct ifaddr *)data;
350	struct ifreq * ifr = (struct ifreq *)data;
351	u_char * ptr;
352	int error, s;
353
354	error = 0;
355	s = splnet();
356
357	if (sc->sc_dev_ok) {
358		LP_PRINTF("%s(%s): device not properly attached!", __func__,
359			device_xname(dev));
360		error = ENODEV;
361		goto end;
362	}
363
364	switch (cmd) {
365
366	case SIOCSIFDSTADDR:
367		if (ifa->ifa_addr->sa_family != AF_INET)
368			error = EAFNOSUPPORT;
369		break;
370
371	case SIOCINITIFADDR:
372		if (ifa->ifa_addr->sa_family != AF_INET) {
373			error = EAFNOSUPPORT;
374			break;
375		}
376		ifp->if_flags |= IFF_UP;
377	/* FALLTHROUGH */
378	case SIOCSIFFLAGS:
379		if (cmd == SIOCSIFFLAGS) {
380			if ((error = ifioctl_common(ifp, cmd, data)) != 0)
381				break;
382		}
383		if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_UP) {
384			if ((error = ppbus_request_bus(ppbus, dev, 0, 0)))
385				break;
386			error = ppbus_set_mode(ppbus, PPBUS_COMPATIBLE, 0);
387			if (error)
388				break;
389
390			error = ppbus_add_handler(ppbus, lp_intr, dev);
391			if (error) {
392				LP_PRINTF("%s(%s): unable to register interrupt"
393					" callback.\n", __func__,
394					device_xname(dev));
395				ppbus_release_bus(ppbus, dev, 0, 0);
396				break;
397			}
398
399			/* Allocate a buffer if necessary */
400			if (sc->sc_ifbuf == NULL) {
401				sc->sc_ifbuf = malloc(sc->sc_if.if_mtu +
402					MLPIPHDRLEN, M_DEVBUF, M_WAITOK);
403			}
404
405			ppbus_wctr(ppbus, IRQENABLE);
406			ifp->if_flags |= IFF_RUNNING;
407		}
408		if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_RUNNING) {
409			ppbus_remove_handler(ppbus, lp_intr);
410			error = ppbus_release_bus(ppbus, dev, 0, 0);
411			ifp->if_flags &= ~IFF_RUNNING;
412		}
413		/* Go quiescent */
414		ppbus_wdtr(ppbus, 0);
415		break;
416
417	case SIOCSIFMTU:
418		if (sc->sc_if.if_mtu == ifr->ifr_mtu)
419			break;
420		ptr = sc->sc_ifbuf;
421		sc->sc_ifbuf = malloc(ifr->ifr_mtu + MLPIPHDRLEN, M_DEVBUF,
422			M_WAITOK);
423		if (ptr)
424			free(ptr,M_DEVBUF);
425		/*FALLTHROUGH*/
426	case SIOCGIFMTU:
427		if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET)
428			error = 0;
429		break;
430
431	case SIOCADDMULTI:
432	case SIOCDELMULTI:
433		if (ifr == NULL) {
434			error = EAFNOSUPPORT;		/* XXX */
435			break;
436		}
437		switch (ifreq_getaddr(cmd, ifr)->sa_family) {
438		case AF_INET:
439			break;
440		default:
441			splx(s);
442			return EAFNOSUPPORT;
443		}
444		break;
445
446	case SIOCGIFMEDIA:
447		/*
448		 * No ifmedia support at this stage; maybe use it
449		 * in future for eg. protocol selection.
450		 */
451	default:
452		LP_PRINTF("LP:ioctl(0x%lx)\n", cmd);
453		error = ifioctl_common(ifp, cmd, data);
454	}
455
456end:
457	splx(s);
458	return error;
459}
460
461static inline int
462clpoutbyte(u_char byte, int spin, device_t ppbus)
463{
464	int s = spin;
465	ppbus_wdtr(ppbus, ctxmitl[byte]);
466	while (ppbus_rstr(ppbus) & CLPIP_SHAKE) {
467		if (--s == 0) {
468			return 1;
469		}
470	}
471	s = spin;
472	ppbus_wdtr(ppbus, ctxmith[byte]);
473	while (!(ppbus_rstr(ppbus) & CLPIP_SHAKE)) {
474		if (--s == 0) {
475			return 1;
476		}
477	}
478	return 0;
479}
480
481static inline int
482clpinbyte(int spin, device_t ppbus)
483{
484	u_char c, cl;
485	int s = spin;
486
487	while (ppbus_rstr(ppbus) & CLPIP_SHAKE) {
488		if (!--s) {
489			return -1;
490		}
491	}
492	cl = ppbus_rstr(ppbus);
493	ppbus_wdtr(ppbus, 0x10);
494
495	s = spin;
496	while (!(ppbus_rstr(ppbus) & CLPIP_SHAKE)) {
497		if (!--s) {
498			return -1;
499		}
500	}
501	c = ppbus_rstr(ppbus);
502	ppbus_wdtr(ppbus, 0x00);
503
504	return (ctrecvl[cl] | ctrecvh[c]);
505}
506
507static void
508lptap(struct ifnet *ifp, struct mbuf *m, u_int direction)
509{
510	/*
511	 * Send a packet through bpf. We need to prepend the address family
512	 * as a four byte field. Cons up a dummy header to pacify bpf. This
513	 * is safe because bpf will only read from the mbuf (i.e., it won't
514	 * try to free it or keep a pointer to it).
515	 */
516	u_int32_t af = AF_INET;
517	struct mbuf m0;
518
519	m0.m_type = MT_DATA;
520	m0.m_next = m;
521	m0.m_nextpkt = NULL;
522	m0.m_owner = NULL;
523	m0.m_len = sizeof(u_int32_t);
524	m0.m_data = (char *)&af;
525	m0.m_flags = 0;
526	bpf_mtap(ifp, &m0, direction);
527}
528
529/* Soft interrupt handler called by hardware interrupt handler */
530static void
531lp_intr(void *arg)
532{
533	device_t dev = (device_t)arg;
534        device_t ppbus = device_parent(dev);
535	struct lp_softc * sc = device_private(dev);
536	struct ifnet * ifp = &sc->sc_if;
537	struct mbuf *top;
538	int len, s, j;
539	u_char *bp;
540	u_char c, cl;
541
542	s = splnet();
543
544	/* Do nothing if device not properly attached */
545	if (sc->sc_dev_ok) {
546		LP_PRINTF("%s(%s): device not properly attached!", __func__,
547			device_xname(dev));
548		goto done;
549	}
550
551	/* Do nothing if interface is not up */
552	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
553		goto done;
554
555	/* If other side is no longer transmitting, do nothing */
556	if (!(ppbus_rstr(ppbus) & LPIP_SHAKE))
557		goto done;
558
559	/* Disable interrupts until we finish */
560	ppbus_wctr(ppbus, ~IRQENABLE);
561
562	top = NULL;
563	bp = sc->sc_ifbuf;
564	/* Linux/crynwyr protocol receiving */
565	if (ifp->if_flags & IFF_LINK0) {
566		/* Ack. the request */
567		ppbus_wdtr(ppbus, 0x01);
568
569		/* Get the packet length */
570		j = clpinbyte(LPMAXSPIN2, ppbus);
571		if (j == -1)
572			goto err;
573		len = j;
574		j = clpinbyte(LPMAXSPIN2, ppbus);
575		if (j == -1)
576			goto err;
577		len = len + (j << 8);
578		if (len > ifp->if_mtu + MLPIPHDRLEN)
579			goto err;
580
581		while (len--) {
582			j = clpinbyte(LPMAXSPIN2, ppbus);
583			if (j == -1) {
584				goto err;
585			}
586			*bp++ = j;
587		}
588		/* Get and ignore checksum */
589		j = clpinbyte(LPMAXSPIN2, ppbus);
590		if (j == -1) {
591			goto err;
592		}
593
594		/* Return to idle state */
595		ppbus_wdtr(ppbus, 0);
596		len = bp - sc->sc_ifbuf;
597		if (len <= CLPIPHDRLEN)
598			goto err;
599		len -= CLPIPHDRLEN;
600		top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, ifp);
601	}
602	/* FreeBSD protocol receiving */
603	else {
604		len = ifp->if_mtu + LPIPHDRLEN;
605		while (len--) {
606			cl = ppbus_rstr(ppbus);
607			ppbus_wdtr(ppbus, 0x08);
608
609			j = LPMAXSPIN2;
610			while ((ppbus_rstr(ppbus) & LPIP_SHAKE)) {
611				if (!--j)
612					goto err;
613			}
614
615			c = ppbus_rstr(ppbus);
616			ppbus_wdtr(ppbus, 0);
617
618			*bp++= trecvh[cl] | trecvl[c];
619
620			j = LPMAXSPIN2;
621			while (!((cl = ppbus_rstr(ppbus)) & LPIP_SHAKE)) {
622				if (cl != c &&
623					(((cl = ppbus_rstr(ppbus)) ^ 0xb8) &
624					0xf8) == (c & 0xf8))
625					goto end;
626				if (!--j)
627					goto err;
628			}
629		}
630
631end:
632		len = bp - sc->sc_ifbuf;
633		if (len <= LPIPHDRLEN)
634			goto err;
635		len -= LPIPHDRLEN;
636		top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, ifp);
637	}
638
639	if (top == NULL) {
640		if_statinc(ifp, if_iqdrops);
641		goto err;
642	}
643	if (ifp->if_bpf) {
644		lptap(ifp, top, BPF_D_IN);
645	}
646	if (__predict_false(!pktq_enqueue(ip_pktq, top, 0))) {
647		if_statinc(ifp, if_iqdrops);
648		m_freem(top);
649		goto err;
650	}
651	if_statinc(ifp, if_ipackets);
652	if_statadd(ifp, if_ibytes, len);
653	sc->sc_iferrs = 0;
654
655	goto done;
656
657err:
658	/* Return to idle state */
659	ppbus_wdtr(ppbus, 0);
660	if_statinc(ifp, if_ierrors);
661	sc->sc_iferrs++;
662	LP_PRINTF("R");
663	/* Disable interface if there are too many errors */
664	if (sc->sc_iferrs > LPMAXERRS) {
665		aprint_error_dev(dev, "Too many consecutive errors, going off-line.\n");
666		ppbus_wctr(ppbus, ~IRQENABLE);
667		if_down(ifp);
668		sc->sc_iferrs = 0;
669	}
670
671done:
672	/* Re-enable interrupts */
673	ppbus_wctr(ppbus, IRQENABLE);
674	/* If interface is not active, send some packets */
675	if ((ifp->if_flags & IFF_OACTIVE) == 0)
676		lpstart(ifp);
677	splx(s);
678	return;
679}
680
681static inline int
682lpoutbyte(u_char byte, int spin, device_t ppbus)
683{
684	int s = spin;
685	ppbus_wdtr(ppbus, txmith[byte]);
686	while (!(ppbus_rstr(ppbus) & LPIP_SHAKE)) {
687		if (--s == 0)
688			return 1;
689	}
690	s = spin;
691	ppbus_wdtr(ppbus, txmitl[byte]);
692	while (ppbus_rstr(ppbus) & LPIP_SHAKE) {
693		if (--s == 0)
694			return 1;
695	}
696	return 0;
697}
698
699/* Queue a packet for delivery */
700static int
701lpoutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
702    const struct rtentry *rt)
703{
704	struct lp_softc * sc = ifp->if_softc;
705	device_t dev = sc->ppbus_dev.sc_dev;
706	device_t ppbus = device_parent(dev);
707	int err;
708	int s;
709
710	s = splnet();
711
712	if (sc->sc_dev_ok) {
713		LP_PRINTF("%s(%s): device not properly attached!", __func__,
714			device_xname(dev));
715		err = ENODEV;
716		goto endoutput;
717	}
718
719	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
720		err = ENETDOWN;
721		goto endoutput;
722	}
723
724	/* Only support INET */
725	if (dst->sa_family != AF_INET) {
726		LP_PRINTF("%s: af%d not supported\n", ifp->if_xname,
727		    dst->sa_family);
728		if_statinc(ifp, if_noproto);
729		err = EAFNOSUPPORT;
730		goto endoutput;
731	}
732
733	IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family);
734	IFQ_ENQUEUE(&ifp->if_snd, m, err);
735	if (err == 0) {
736		if ((ifp->if_flags & IFF_OACTIVE) == 0)
737			lpstart(ifp);
738	} else {
739		if_statinc(ifp, if_oerrors);
740		sc->sc_iferrs++;
741		LP_PRINTF("Q");
742
743		/* Disable interface if there are too many errors */
744		if (sc->sc_iferrs > LPMAXERRS) {
745			aprint_error_dev(dev, "Too many errors, going off-line.\n");
746			ppbus_wctr(ppbus, ~IRQENABLE);
747			if_down(ifp);
748			sc->sc_iferrs = 0;
749		}
750	}
751
752endoutput:
753	if ((err != 0) && (err != ENOBUFS))
754		m_freem(m);
755	splx(s);
756	return err;
757}
758
759/* Send routine: send packets over PLIP cable. Call at splnet(). */
760void
761lpstart(struct ifnet * ifp)
762{
763	struct lp_softc * lp = ifp->if_softc;
764	device_t dev = lp->ppbus_dev.sc_dev;
765	device_t ppbus = device_parent(dev);
766	struct mbuf * mm;
767	struct mbuf * m;
768	u_char * cp;
769	int err, i, len, spin, count;
770	u_char str, chksum;
771
772	if (lp->sc_dev_ok) {
773		LP_PRINTF("%s(%s): device not properly attached!", __func__,
774			device_xname(dev));
775		return;
776	}
777
778	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
779		return;
780	}
781
782	ifp->if_flags |= IFF_OACTIVE;
783
784	/* Go quiescent */
785	ppbus_wdtr(ppbus, 0);
786
787	/* Output loop */
788	for (;;) {
789		/* Check if there are packets to send */
790		if (IFQ_IS_EMPTY(&ifp->if_snd)) {
791			goto final;
792		}
793		/* Try to send a packet, dequeue it later if successful */
794		IFQ_POLL(&ifp->if_snd, m);
795		if (m == NULL)
796			goto final;
797
798		str = ppbus_rstr(ppbus);
799		/* Wait until other side is not transmitting */
800		if ((str & LPIP_SHAKE) ||
801			((ifp->if_flags & IFF_LINK0) && !(str & CLPIP_SHAKE))) {
802			LP_PRINTF("&");
803			if (++lp->sc_xmit_rtry > LPMAXRTRY) {
804				aprint_error_dev(dev, "Too many retries while channel "
805					"busy, going off-line.\n");
806				ppbus_wctr(ppbus, ~IRQENABLE);
807				if_down(ifp);
808				lp->sc_xmit_rtry = 0;
809			}
810			goto final;
811		}
812		lp->sc_xmit_rtry = 0;
813
814		/* Disable interrupt generation */
815		ppbus_wctr(ppbus, ~IRQENABLE);
816
817		err = 1;
818
819		/* Output packet for Linux/crynwyr compatible protocol */
820		if (ifp->if_flags & IFF_LINK0) {
821			/* Calculate packet length */
822			count = 14;		/* Ethernet header len */
823			for (mm = m; mm; mm = mm->m_next) {
824				count += mm->m_len;
825			}
826
827			/* Alert other end to pending packet */
828			spin = LPMAXSPIN1;
829			ppbus_wdtr(ppbus, 0x08);
830			while ((ppbus_rstr(ppbus) & 0x08) == 0) {
831				if (--spin == 0) {
832					goto nend;
833				}
834			}
835
836			if (clpoutbyte(count & 0xFF, LPMAXSPIN1, ppbus))
837				goto nend;
838			if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, ppbus))
839				goto nend;
840
841			/* Send dummy ethernet header */
842			chksum = 0;
843			for (i = 0; i < 12; i++) {
844				if (clpoutbyte(i, LPMAXSPIN1, ppbus))
845					goto nend;
846				chksum += i;
847			}
848
849			if (clpoutbyte(0x08, LPMAXSPIN1, ppbus))
850				goto nend;
851			if (clpoutbyte(0x00, LPMAXSPIN1, ppbus))
852				goto nend;
853			chksum += 0x08 + 0x00;		/* Add into checksum */
854
855			mm = m;
856			do {
857				cp = mtod(mm, u_char *);
858				len = mm->m_len;
859				while (len--) {
860					if (clpoutbyte(*cp, LPMAXSPIN2, ppbus))
861						goto nend;
862					chksum += *cp++;
863				}
864			} while ((mm = mm->m_next));
865
866			/* Send checksum */
867			if (clpoutbyte(chksum, LPMAXSPIN2, ppbus))
868				goto nend;
869
870			/* No errors */
871			err = 0;
872			/* Go quiescent */
873			ppbus_wdtr(ppbus, 0);
874		}
875		/* Output packet for FreeBSD compatible protocol */
876		else {
877			/* We need a sensible value if we abort */
878			cp = NULL;
879
880			if (lpoutbyte(0x08, LPMAXSPIN1, ppbus))
881				goto end;
882			if (lpoutbyte(0x00, LPMAXSPIN2, ppbus))
883				goto end;
884
885			mm = m;
886			do {
887				cp = mtod(mm,u_char *);
888				len = mm->m_len;
889				while (len--)
890					if (lpoutbyte(*cp++, LPMAXSPIN2, ppbus))
891						goto end;
892			} while ((mm = mm->m_next));
893
894			/* no errors were encountered */
895			err = 0;
896
897end:
898			if (cp)
899				ppbus_wdtr(ppbus, txmitl[*(--cp)] ^ 0x17);
900			else
901				ppbus_wdtr(ppbus, txmitl['\0'] ^ 0x17);
902		}
903
904nend:
905		/* Re-enable interrupt generation */
906		ppbus_wctr(ppbus, IRQENABLE);
907
908		if (err) {
909			/* Go quiescent */
910			ppbus_wdtr(ppbus, 0);
911
912			if_statinc(ifp, if_oerrors);
913			lp->sc_iferrs++;
914			LP_PRINTF("X");
915
916			/* Disable interface if there are too many errors */
917			if (lp->sc_iferrs > LPMAXERRS) {
918				aprint_error_dev(dev, "Too many errors, going off-line.\n");
919				ppbus_wctr(ppbus, ~IRQENABLE);
920				if_down(ifp);
921				lp->sc_iferrs = 0;
922				goto final;
923			}
924		} else {
925			/* Dequeue packet on success */
926			IFQ_DEQUEUE(&ifp->if_snd, m);
927			if(ifp->if_bpf)
928				lptap(ifp, m, BPF_D_OUT);
929			if_statinc(ifp, if_opackets);
930			if_statadd(ifp, if_obytes, m->m_pkthdr.len);
931			m_freem(m);
932		}
933	}
934
935final:
936	ifp->if_flags &= ~IFF_OACTIVE;
937	return;
938}
939