1 /* $NetBSD: if_plip.c,v 1.22 2008/11/07 00:20:12 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.22 2008/11/07 00:20:12 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(device_t, cfdata_t, void *); 178 static void lp_attach(device_t, device_t, void *); 179 static int lp_detach(device_t, 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_NEW(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(device_t parent, cfdata_t 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(device_t parent, device_t self, void *aux) 221 { 222 struct lp_softc * lp = device_private(self); 223 struct ifnet * ifp = &lp->sc_if; 224 225 lp->ppbus_dev.sc_dev = self; 226 lp->sc_dev_ok = 0; 227 lp->sc_ifbuf = NULL; 228 lp->sc_iferrs = 0; 229 lp->sc_xmit_rtry = 0; 230 231 ifp->if_softc = lp; 232 strlcpy(ifp->if_xname, device_xname(self), IFNAMSIZ); 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(device_t self, int flags) 258 { 259 int error = 0; 260 struct lp_softc * lp = device_private(self); 261 device_t 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 device_xname(self)); 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 device_xname(self)); 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__, device_xname(self), 289 device_xname(ppbus)); 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 lp_softc * sc = ifp->if_softc; 351 device_t dev = sc->ppbus_dev.sc_dev; 352 device_t ppbus = device_parent(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 device_xname(dev)); 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 SIOCINITIFADDR: 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 ((error = ifioctl_common(ifp, cmd, data)) != 0) 384 break; 385 if((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_UP) { 386 if((error = ppbus_request_bus(ppbus, dev, 0, 0))) 387 break; 388 error = ppbus_set_mode(ppbus, PPBUS_COMPATIBLE, 0); 389 if(error) 390 break; 391 392 error = ppbus_add_handler(ppbus, lp_intr, dev); 393 if(error) { 394 LP_PRINTF("%s(%s): unable to register interrupt" 395 " callback.\n", __func__, 396 device_xname(dev)); 397 ppbus_release_bus(ppbus, dev, 0, 0); 398 break; 399 } 400 401 /* Allocate a buffer if necessary */ 402 if(sc->sc_ifbuf == NULL) { 403 sc->sc_ifbuf = malloc(sc->sc_if.if_mtu + 404 MLPIPHDRLEN, M_DEVBUF, M_NOWAIT); 405 if (!sc->sc_ifbuf) { 406 error = ENOBUFS; 407 ppbus_release_bus(ppbus, dev, 0, 0); 408 break; 409 } 410 } 411 412 ppbus_wctr(ppbus, IRQENABLE); 413 ifp->if_flags |= IFF_RUNNING; 414 } 415 if((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_RUNNING) { 416 ppbus_remove_handler(ppbus, lp_intr); 417 error = ppbus_release_bus(ppbus, dev, 0, 0); 418 ifp->if_flags &= ~IFF_RUNNING; 419 } 420 /* Go quiescent */ 421 ppbus_wdtr(ppbus, 0); 422 break; 423 424 case SIOCSIFMTU: 425 if(sc->sc_if.if_mtu == ifr->ifr_mtu) 426 break; 427 ptr = sc->sc_ifbuf; 428 sc->sc_ifbuf = malloc(ifr->ifr_mtu+MLPIPHDRLEN, M_DEVBUF, 429 M_NOWAIT); 430 if (!sc->sc_ifbuf) { 431 sc->sc_ifbuf = ptr; 432 error = ENOBUFS; 433 break; 434 } 435 if(ptr) 436 free(ptr,M_DEVBUF); 437 /*FALLTHROUGH*/ 438 case SIOCGIFMTU: 439 if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET) 440 error = 0; 441 break; 442 443 case SIOCADDMULTI: 444 case SIOCDELMULTI: 445 if (ifr == NULL) { 446 error = EAFNOSUPPORT; /* XXX */ 447 break; 448 } 449 switch (ifreq_getaddr(cmd, ifr)->sa_family) { 450 case AF_INET: 451 break; 452 default: 453 return EAFNOSUPPORT; 454 } 455 break; 456 457 case SIOCGIFMEDIA: 458 /* 459 * No ifmedia support at this stage; maybe use it 460 * in future for eg. protocol selection. 461 */ 462 default: 463 LP_PRINTF("LP:ioctl(0x%lx)\n", cmd); 464 error = ifioctl_common(ifp, cmd, data); 465 } 466 467 end: 468 splx(s); 469 return error; 470 } 471 472 static inline int 473 clpoutbyte (u_char byte, int spin, device_t ppbus) 474 { 475 int s = spin; 476 ppbus_wdtr(ppbus, ctxmitl[byte]); 477 while (ppbus_rstr(ppbus) & CLPIP_SHAKE) { 478 if (--s == 0) { 479 return 1; 480 } 481 } 482 s = spin; 483 ppbus_wdtr(ppbus, ctxmith[byte]); 484 while (!(ppbus_rstr(ppbus) & CLPIP_SHAKE)) { 485 if (--s == 0) { 486 return 1; 487 } 488 } 489 return 0; 490 } 491 492 static inline int 493 clpinbyte (int spin, device_t ppbus) 494 { 495 u_char c, cl; 496 int s = spin; 497 498 while(ppbus_rstr(ppbus) & CLPIP_SHAKE) { 499 if(!--s) { 500 return -1; 501 } 502 } 503 cl = ppbus_rstr(ppbus); 504 ppbus_wdtr(ppbus, 0x10); 505 506 s = spin; 507 while(!(ppbus_rstr(ppbus) & CLPIP_SHAKE)) { 508 if(!--s) { 509 return -1; 510 } 511 } 512 c = ppbus_rstr(ppbus); 513 ppbus_wdtr(ppbus, 0x00); 514 515 return (ctrecvl[cl] | ctrecvh[c]); 516 } 517 518 #if NBPFILTER > 0 519 static void 520 lptap(struct ifnet *ifp, struct mbuf *m) 521 { 522 /* 523 * Send a packet through bpf. We need to prepend the address family 524 * as a four byte field. Cons up a dummy header to pacify bpf. This 525 * is safe because bpf will only read from the mbuf (i.e., it won't 526 * try to free it or keep a pointer to it). 527 */ 528 u_int32_t af = AF_INET; 529 struct mbuf m0; 530 531 m0.m_next = m; 532 m0.m_len = sizeof(u_int32_t); 533 m0.m_data = (char *)⁡ 534 bpf_mtap(ifp->if_bpf, &m0); 535 } 536 #endif 537 538 /* Soft interrupt handler called by hardware interrupt handler */ 539 static void 540 lp_intr (void *arg) 541 { 542 device_t dev = (device_t)arg; 543 device_t ppbus = device_parent(dev); 544 struct lp_softc * sc = device_private(dev); 545 struct ifnet * ifp = &sc->sc_if; 546 struct mbuf *top; 547 int len, s, j; 548 u_char *bp; 549 u_char c, cl; 550 551 s = splnet(); 552 553 /* Do nothing if device not properly attached */ 554 if(sc->sc_dev_ok) { 555 LP_PRINTF("%s(%s): device not properly attached!", __func__, 556 device_xname(dev)); 557 goto done; 558 } 559 560 /* Do nothing if interface is not up */ 561 if((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 562 goto done; 563 564 /* If other side is no longer transmitting, do nothing */ 565 if(!(ppbus_rstr(ppbus) & LPIP_SHAKE)) 566 goto done; 567 568 /* Disable interrupts until we finish */ 569 ppbus_wctr(ppbus, ~IRQENABLE); 570 571 top = NULL; 572 bp = sc->sc_ifbuf; 573 /* Linux/crynwyr protocol receiving */ 574 if(ifp->if_flags & IFF_LINK0) { 575 /* Ack. the request */ 576 ppbus_wdtr(ppbus, 0x01); 577 578 /* Get the packet length */ 579 j = clpinbyte(LPMAXSPIN2, ppbus); 580 if(j == -1) 581 goto err; 582 len = j; 583 j = clpinbyte(LPMAXSPIN2, ppbus); 584 if(j == -1) 585 goto err; 586 len = len + (j << 8); 587 if(len > ifp->if_mtu + MLPIPHDRLEN) 588 goto err; 589 590 while(len--) { 591 j = clpinbyte(LPMAXSPIN2, ppbus); 592 if (j == -1) { 593 goto err; 594 } 595 *bp++ = j; 596 } 597 /* Get and ignore checksum */ 598 j = clpinbyte(LPMAXSPIN2, ppbus); 599 if(j == -1) { 600 goto err; 601 } 602 603 /* Return to idle state */ 604 ppbus_wdtr(ppbus, 0); 605 len = bp - sc->sc_ifbuf; 606 if (len <= CLPIPHDRLEN) 607 goto err; 608 len -= CLPIPHDRLEN; 609 top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, ifp, NULL); 610 } 611 /* FreeBSD protocol receiving */ 612 else { 613 len = ifp->if_mtu + LPIPHDRLEN; 614 while(len--) { 615 cl = ppbus_rstr(ppbus); 616 ppbus_wdtr(ppbus, 0x08); 617 618 j = LPMAXSPIN2; 619 while((ppbus_rstr(ppbus) & LPIP_SHAKE)) { 620 if(!--j) goto err; 621 } 622 623 c = ppbus_rstr(ppbus); 624 ppbus_wdtr(ppbus, 0); 625 626 *bp++= trecvh[cl] | trecvl[c]; 627 628 j = LPMAXSPIN2; 629 while(!((cl=ppbus_rstr(ppbus)) & LPIP_SHAKE)) { 630 if(cl != c && 631 (((cl = ppbus_rstr(ppbus)) ^ 0xb8) & 632 0xf8) == (c & 0xf8)) 633 goto end; 634 if(!--j) goto err; 635 } 636 } 637 638 end: 639 len = bp - sc->sc_ifbuf; 640 if(len <= LPIPHDRLEN) 641 goto err; 642 len -= LPIPHDRLEN; 643 top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, ifp, NULL); 644 } 645 646 /* Do nothing if mbuf was not created or the queue is full */ 647 if((top == NULL) || (IF_QFULL(&ipintrq))) { 648 IF_DROP(&ipintrq); 649 ifp->if_iqdrops++; 650 LP_PRINTF("DROP"); 651 goto err; 652 } 653 #if NBPFILTER > 0 654 if(ifp->if_bpf) 655 lptap(ifp, top); 656 #endif 657 IF_ENQUEUE(&ipintrq, top); 658 schednetisr(NETISR_IP); 659 ifp->if_ipackets++; 660 ifp->if_ibytes += len; 661 sc->sc_iferrs = 0; 662 663 goto done; 664 665 err: 666 /* Return to idle state */ 667 ppbus_wdtr(ppbus, 0); 668 ifp->if_ierrors++; 669 sc->sc_iferrs++; 670 LP_PRINTF("R"); 671 /* Disable interface if there are too many errors */ 672 if(sc->sc_iferrs > LPMAXERRS) { 673 aprint_error_dev(dev, "Too many consecutive errors, going off-line.\n"); 674 ppbus_wctr(ppbus, ~IRQENABLE); 675 if_down(ifp); 676 sc->sc_iferrs = 0; 677 } 678 679 done: 680 /* Re-enable interrupts */ 681 ppbus_wctr(ppbus, IRQENABLE); 682 /* If interface is not active, send some packets */ 683 if((ifp->if_flags & IFF_OACTIVE) == 0) 684 lpstart(ifp); 685 splx(s); 686 return; 687 } 688 689 static inline int 690 lpoutbyte(u_char byte, int spin, device_t ppbus) 691 { 692 int s = spin; 693 ppbus_wdtr(ppbus, txmith[byte]); 694 while(!(ppbus_rstr(ppbus) & LPIP_SHAKE)) { 695 if(--s == 0) 696 return 1; 697 } 698 s = spin; 699 ppbus_wdtr(ppbus, txmitl[byte]); 700 while(ppbus_rstr(ppbus) & LPIP_SHAKE) { 701 if(--s == 0) 702 return 1; 703 } 704 return 0; 705 } 706 707 /* Queue a packet for delivery */ 708 static int 709 lpoutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 710 struct rtentry *rt) 711 { 712 struct lp_softc * sc = ifp->if_softc; 713 device_t dev = sc->ppbus_dev.sc_dev; 714 device_t ppbus = device_parent(dev); 715 ALTQ_DECL(struct altq_pktattr pktattr;) 716 int err; 717 int s; 718 719 s = splnet(); 720 721 if(sc->sc_dev_ok) { 722 LP_PRINTF("%s(%s): device not properly attached!", __func__, 723 device_xname(dev)); 724 err = ENODEV; 725 goto endoutput; 726 } 727 728 if((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 729 err = ENETDOWN; 730 goto endoutput; 731 } 732 733 /* Only support INET */ 734 if(dst->sa_family != AF_INET) { 735 LP_PRINTF("%s: af%d not supported\n", ifp->if_xname, 736 dst->sa_family); 737 ifp->if_noproto++; 738 err = EAFNOSUPPORT; 739 goto endoutput; 740 } 741 742 IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr); 743 IFQ_ENQUEUE(&ifp->if_snd, m, NULL, err); 744 if(err == 0) { 745 if((ifp->if_flags & IFF_OACTIVE) == 0) 746 lpstart(ifp); 747 } 748 else { 749 ifp->if_oerrors++; 750 sc->sc_iferrs++; 751 LP_PRINTF("Q"); 752 753 /* Disable interface if there are too many errors */ 754 if(sc->sc_iferrs > LPMAXERRS) { 755 aprint_error_dev(dev, "Too many errors, going off-line.\n"); 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 device_t dev = lp->ppbus_dev.sc_dev; 775 device_t 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 device_xname(dev)); 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 aprint_error_dev(dev, "Too many retries while channel " 815 "busy, going off-line.\n"); 816 ppbus_wctr(ppbus, ~IRQENABLE); 817 if_down(ifp); 818 lp->sc_xmit_rtry = 0; 819 } 820 goto final; 821 } 822 lp->sc_xmit_rtry = 0; 823 824 /* Disable interrupt generation */ 825 ppbus_wctr(ppbus, ~IRQENABLE); 826 827 err = 1; 828 829 /* Output packet for Linux/crynwyr compatible protocol */ 830 if(ifp->if_flags & IFF_LINK0) { 831 /* Calculate packet length */ 832 count = 14; /* Ethernet header len */ 833 for(mm = m; mm; mm = mm->m_next) { 834 count += mm->m_len; 835 } 836 837 /* Alert other end to pending packet */ 838 spin = LPMAXSPIN1; 839 ppbus_wdtr(ppbus, 0x08); 840 while((ppbus_rstr(ppbus) & 0x08) == 0) { 841 if (--spin == 0) { 842 goto nend; 843 } 844 } 845 846 if(clpoutbyte(count & 0xFF, LPMAXSPIN1, ppbus)) 847 goto nend; 848 if(clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, ppbus)) 849 goto nend; 850 851 /* Send dummy ethernet header */ 852 chksum = 0; 853 for(i = 0; i < 12; i++) { 854 if(clpoutbyte(i, LPMAXSPIN1, ppbus)) 855 goto nend; 856 chksum += i; 857 } 858 859 if(clpoutbyte(0x08, LPMAXSPIN1, ppbus)) 860 goto nend; 861 if(clpoutbyte(0x00, LPMAXSPIN1, ppbus)) 862 goto nend; 863 chksum += 0x08 + 0x00; /* Add into checksum */ 864 865 mm = m; 866 do { 867 cp = mtod(mm, u_char *); 868 len = mm->m_len; 869 while(len--) { 870 if(clpoutbyte(*cp, LPMAXSPIN2, ppbus)) 871 goto nend; 872 chksum += *cp++; 873 } 874 } while ((mm = mm->m_next)); 875 876 /* Send checksum */ 877 if(clpoutbyte(chksum, LPMAXSPIN2, ppbus)) 878 goto nend; 879 880 /* No errors */ 881 err = 0; 882 /* Go quiescent */ 883 ppbus_wdtr(ppbus, 0); 884 } 885 /* Output packet for FreeBSD compatible protocol */ 886 else { 887 /* We need a sensible value if we abort */ 888 cp = NULL; 889 890 if(lpoutbyte(0x08, LPMAXSPIN1, ppbus)) 891 goto end; 892 if(lpoutbyte(0x00, LPMAXSPIN2, ppbus)) 893 goto end; 894 895 mm = m; 896 do { 897 cp = mtod(mm,u_char *); 898 len = mm->m_len; 899 while(len--) 900 if(lpoutbyte(*cp++, LPMAXSPIN2, ppbus)) 901 goto end; 902 } while ((mm = mm->m_next)); 903 904 /* no errors were encountered */ 905 err = 0; 906 907 end: 908 if(cp) 909 ppbus_wdtr(ppbus, txmitl[*(--cp)] ^ 0x17); 910 else 911 ppbus_wdtr(ppbus, txmitl['\0'] ^ 0x17); 912 } 913 914 nend: 915 /* Re-enable interrupt generation */ 916 ppbus_wctr(ppbus, IRQENABLE); 917 918 if(err) { 919 /* Go quiescent */ 920 ppbus_wdtr(ppbus, 0); 921 922 ifp->if_oerrors++; 923 lp->sc_iferrs++; 924 LP_PRINTF("X"); 925 926 /* Disable interface if there are too many errors */ 927 if(lp->sc_iferrs > LPMAXERRS) { 928 aprint_error_dev(dev, "Too many errors, going off-line.\n"); 929 ppbus_wctr(ppbus, ~IRQENABLE); 930 if_down(ifp); 931 lp->sc_iferrs = 0; 932 goto final; 933 } 934 } 935 else { 936 /* Dequeue packet on success */ 937 IFQ_DEQUEUE(&ifp->if_snd, m); 938 #if NBPFILTER > 0 939 if(ifp->if_bpf) 940 lptap(ifp, m); 941 #endif 942 ifp->if_opackets++; 943 ifp->if_obytes += m->m_pkthdr.len; 944 m_freem(m); 945 } 946 } 947 948 final: 949 ifp->if_flags &= ~IFF_OACTIVE; 950 return; 951 } 952