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