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 *)⁡
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