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