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