xref: /netbsd-src/sys/dev/ppbus/if_plip.c (revision 2434a4afee45bb27c98b5dafb64e6396c9a66398)
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
158 static int volatile lpflag = 1;
159 #else
160 static int volatile lpflag = 0;
161 #endif
162 
163 /* Tx/Rsv tables for the lp interface */
164 static u_char *txmith;
165 #define txmitl (txmith+(1*LPIPTBLSIZE))
166 #define trecvh (txmith+(2*LPIPTBLSIZE))
167 #define trecvl (txmith+(3*LPIPTBLSIZE))
168 static u_char *ctxmith;
169 #define ctxmitl (ctxmith+(1*LPIPTBLSIZE))
170 #define ctrecvh (ctxmith+(2*LPIPTBLSIZE))
171 #define ctrecvl (ctxmith+(3*LPIPTBLSIZE))
172 static uint16_t lp_count = 0;
173 
174 /* Autoconf functions */
175 static int lp_probe(device_t, cfdata_t, void *);
176 static void lp_attach(device_t, device_t, void *);
177 static int lp_detach(device_t, int);
178 
179 /* Soft config data */
180 struct 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 */
190 CFATTACH_DECL_NEW(plip, sizeof(struct lp_softc), lp_probe, lp_attach, lp_detach,
191 	NULL);
192 
193 /* Functions for the lp interface */
194 static void lpinittables(void);
195 static void lpfreetables(void);
196 static int lpioctl(struct ifnet *, u_long, void *);
197 static int lpoutput(struct ifnet *, struct mbuf *, const struct sockaddr *,
198     const struct rtentry *);
199 static void lpstart(struct ifnet *);
200 static void lp_intr(void *);
201 
202 
203 static int
lp_probe(device_t parent,cfdata_t match,void * aux)204 lp_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 
217 static void
lp_attach(device_t parent,device_t self,void * aux)218 lp_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 
252 static int
lp_detach(device_t self,int flags)253 lp_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  */
304 static void
lpinittables(void)305 lpinittables(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 */
331 static void
lpfreetables(void)332 lpfreetables(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. */
343 static int
lpioctl(struct ifnet * ifp,u_long cmd,void * data)344 lpioctl(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 
456 end:
457 	splx(s);
458 	return error;
459 }
460 
461 static inline int
clpoutbyte(u_char byte,int spin,device_t ppbus)462 clpoutbyte(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 
481 static inline int
clpinbyte(int spin,device_t ppbus)482 clpinbyte(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 
507 static void
lptap(struct ifnet * ifp,struct mbuf * m,u_int direction)508 lptap(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 */
530 static void
lp_intr(void * arg)531 lp_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 
631 end:
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 
657 err:
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 
671 done:
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 
681 static inline int
lpoutbyte(u_char byte,int spin,device_t ppbus)682 lpoutbyte(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 */
700 static int
lpoutput(struct ifnet * ifp,struct mbuf * m,const struct sockaddr * dst,const struct rtentry * rt)701 lpoutput(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 
752 endoutput:
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(). */
760 void
lpstart(struct ifnet * ifp)761 lpstart(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 
897 end:
898 			if (cp)
899 				ppbus_wdtr(ppbus, txmitl[*(--cp)] ^ 0x17);
900 			else
901 				ppbus_wdtr(ppbus, txmitl['\0'] ^ 0x17);
902 		}
903 
904 nend:
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 
935 final:
936 	ifp->if_flags &= ~IFF_OACTIVE;
937 	return;
938 }
939