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