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