1 /* $NetBSD: if_plip.c,v 1.5 2004/02/10 21:55:38 jdolecek 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.5 2004/02/10 21:55:38 jdolecek 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 <machine/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, caddr_t); 199 static int lpoutput(struct ifnet *, struct mbuf *, 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 = (struct lp_softc *) 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 = self; 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 = (struct lp_softc *) self; 261 struct device * ppbus = self->dv_parent; 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, caddr_t data) 349 { 350 struct device * dev = ifp->if_softc; 351 struct device * ppbus = dev->dv_parent; 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 sc->sc_if.if_mtu = ifr->ifr_mtu; 436 break; 437 438 case SIOCGIFMTU: 439 ifr->ifr_mtu = sc->sc_if.if_mtu; 440 break; 441 442 case SIOCADDMULTI: 443 case SIOCDELMULTI: 444 if (ifr == NULL) { 445 error = EAFNOSUPPORT; /* XXX */ 446 break; 447 } 448 switch (ifr->ifr_addr.sa_family) { 449 case AF_INET: 450 break; 451 default: 452 return EAFNOSUPPORT; 453 } 454 break; 455 456 case SIOCGIFMEDIA: 457 /* 458 * No ifmedia support at this stage; maybe use it 459 * in future for eg. protocol selection. 460 */ 461 default: 462 LP_PRINTF("LP:ioctl(0x%lx)\n", cmd); 463 error = EINVAL; 464 } 465 466 end: 467 splx(s); 468 return error; 469 } 470 471 static __inline int 472 clpoutbyte (u_char byte, int spin, struct device * ppbus) 473 { 474 int s = spin; 475 ppbus_wdtr(ppbus, ctxmitl[byte]); 476 while (ppbus_rstr(ppbus) & CLPIP_SHAKE) { 477 if (--s == 0) { 478 return 1; 479 } 480 } 481 s = spin; 482 ppbus_wdtr(ppbus, ctxmith[byte]); 483 while (!(ppbus_rstr(ppbus) & CLPIP_SHAKE)) { 484 if (--s == 0) { 485 return 1; 486 } 487 } 488 return 0; 489 } 490 491 static __inline int 492 clpinbyte (int spin, struct device * ppbus) 493 { 494 u_char c, cl; 495 int s = spin; 496 497 while(ppbus_rstr(ppbus) & CLPIP_SHAKE) { 498 if(!--s) { 499 return -1; 500 } 501 } 502 cl = ppbus_rstr(ppbus); 503 ppbus_wdtr(ppbus, 0x10); 504 505 s = spin; 506 while(!(ppbus_rstr(ppbus) & CLPIP_SHAKE)) { 507 if(!--s) { 508 return -1; 509 } 510 } 511 c = ppbus_rstr(ppbus); 512 ppbus_wdtr(ppbus, 0x00); 513 514 return (ctrecvl[cl] | ctrecvh[c]); 515 } 516 517 #if NBPFILTER > 0 518 static void 519 lptap(struct ifnet *ifp, struct mbuf *m) 520 { 521 /* 522 * Send a packet through bpf. We need to prepend the address family 523 * as a four byte field. Cons up a dummy header to pacify bpf. This 524 * is safe because bpf will only read from the mbuf (i.e., it won't 525 * try to free it or keep a pointer to it). 526 */ 527 u_int32_t af = AF_INET; 528 struct mbuf m0; 529 530 m0.m_next = m; 531 m0.m_len = sizeof(u_int32_t); 532 m0.m_data = (char *)⁡ 533 bpf_mtap(ifp->if_bpf, &m0); 534 } 535 #endif 536 537 /* Soft interrupt handler called by hardware interrupt handler */ 538 static void 539 lp_intr (void *arg) 540 { 541 struct device * dev = (struct device *)arg; 542 struct device * ppbus = dev->dv_parent; 543 struct lp_softc * sc = (struct lp_softc *)dev; 544 struct ifnet * ifp = &sc->sc_if; 545 struct mbuf *top; 546 int len, s, j; 547 u_char *bp; 548 u_char c, cl; 549 550 s = splnet(); 551 552 /* Do nothing if device not properly attached */ 553 if(sc->sc_dev_ok) { 554 LP_PRINTF("%s(%s): device not properly attached!", __func__, 555 dev->dv_xname); 556 goto done; 557 } 558 559 /* Do nothing if interface is not up */ 560 if((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 561 goto done; 562 563 /* If other side is no longer transmitting, do nothing */ 564 if(!(ppbus_rstr(ppbus) & LPIP_SHAKE)) 565 goto done; 566 567 /* Disable interrupts until we finish */ 568 ppbus_wctr(ppbus, ~IRQENABLE); 569 570 top = NULL; 571 bp = sc->sc_ifbuf; 572 /* Linux/crynwyr protocol receiving */ 573 if(ifp->if_flags & IFF_LINK0) { 574 /* Ack. the request */ 575 ppbus_wdtr(ppbus, 0x01); 576 577 /* Get the packet length */ 578 j = clpinbyte(LPMAXSPIN2, ppbus); 579 if(j == -1) 580 goto err; 581 len = j; 582 j = clpinbyte(LPMAXSPIN2, ppbus); 583 if(j == -1) 584 goto err; 585 len = len + (j << 8); 586 if(len > ifp->if_mtu + MLPIPHDRLEN) 587 goto err; 588 589 while(len--) { 590 j = clpinbyte(LPMAXSPIN2, ppbus); 591 if (j == -1) { 592 goto err; 593 } 594 *bp++ = j; 595 } 596 /* Get and ignore checksum */ 597 j = clpinbyte(LPMAXSPIN2, ppbus); 598 if(j == -1) { 599 goto err; 600 } 601 602 /* Return to idle state */ 603 ppbus_wdtr(ppbus, 0); 604 len = bp - sc->sc_ifbuf; 605 if (len <= CLPIPHDRLEN) 606 goto err; 607 len -= CLPIPHDRLEN; 608 top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, ifp, NULL); 609 } 610 /* FreeBSD protocol receiving */ 611 else { 612 len = ifp->if_mtu + LPIPHDRLEN; 613 while(len--) { 614 cl = ppbus_rstr(ppbus); 615 ppbus_wdtr(ppbus, 0x08); 616 617 j = LPMAXSPIN2; 618 while((ppbus_rstr(ppbus) & LPIP_SHAKE)) { 619 if(!--j) goto err; 620 } 621 622 c = ppbus_rstr(ppbus); 623 ppbus_wdtr(ppbus, 0); 624 625 *bp++= trecvh[cl] | trecvl[c]; 626 627 j = LPMAXSPIN2; 628 while(!((cl=ppbus_rstr(ppbus)) & LPIP_SHAKE)) { 629 if(cl != c && 630 (((cl = ppbus_rstr(ppbus)) ^ 0xb8) & 631 0xf8) == (c & 0xf8)) 632 goto end; 633 if(!--j) goto err; 634 } 635 } 636 637 end: 638 len = bp - sc->sc_ifbuf; 639 if(len <= LPIPHDRLEN) 640 goto err; 641 len -= LPIPHDRLEN; 642 top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, ifp, NULL); 643 } 644 645 /* Do nothing if mbuf was not created or the queue is full */ 646 if((top == NULL) || (IF_QFULL(&ipintrq))) { 647 IF_DROP(&ipintrq); 648 ifp->if_iqdrops++; 649 LP_PRINTF("DROP"); 650 goto err; 651 } 652 #if NBPFILTER > 0 653 if(ifp->if_bpf) 654 lptap(ifp, top); 655 #endif 656 IF_ENQUEUE(&ipintrq, top); 657 schednetisr(NETISR_IP); 658 ifp->if_ipackets++; 659 ifp->if_ibytes += len; 660 sc->sc_iferrs = 0; 661 662 goto done; 663 664 err: 665 /* Return to idle state */ 666 ppbus_wdtr(ppbus, 0); 667 ifp->if_ierrors++; 668 sc->sc_iferrs++; 669 LP_PRINTF("R"); 670 /* Disable interface if there are too many errors */ 671 if(sc->sc_iferrs > LPMAXERRS) { 672 printf("%s: Too many consecutive errors, going off-line.\n", 673 dev->dv_xname); 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, struct device * 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, struct sockaddr *dst, 710 struct rtentry *rt) 711 { 712 struct device * dev = ifp->if_softc; 713 struct device * ppbus = dev->dv_parent; 714 struct lp_softc * sc = (struct lp_softc *) 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 dev->dv_xname); 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, dst->sa_family, 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 printf("%s: Too many errors, going off-line.\n", 756 dev->dv_xname); 757 ppbus_wctr(ppbus, ~IRQENABLE); 758 if_down(ifp); 759 sc->sc_iferrs = 0; 760 } 761 } 762 763 endoutput: 764 if((err != 0) && (err != ENOBUFS)) 765 m_freem(m); 766 splx(s); 767 return err; 768 } 769 770 /* Send routine: send packets over PLIP cable. Call at splnet(). */ 771 void 772 lpstart(struct ifnet * ifp) 773 { 774 struct lp_softc * lp = ifp->if_softc; 775 struct device * dev = ifp->if_softc; 776 struct device * ppbus = dev->dv_parent; 777 struct mbuf * mm; 778 struct mbuf * m; 779 u_char * cp; 780 int err, i, len, spin, count; 781 u_char str, chksum; 782 783 if(lp->sc_dev_ok) { 784 LP_PRINTF("%s(%s): device not properly attached!", __func__, 785 dev->dv_xname); 786 return; 787 } 788 789 if((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 790 return; 791 } 792 793 ifp->if_flags |= IFF_OACTIVE; 794 795 /* Go quiescent */ 796 ppbus_wdtr(ppbus, 0); 797 798 /* Output loop */ 799 for(;;) { 800 /* Check if there are packets to send */ 801 if(IFQ_IS_EMPTY(&ifp->if_snd)) { 802 goto final; 803 } 804 /* Try to send a packet, dequeue it later if successful */ 805 IFQ_POLL(&ifp->if_snd, m); 806 if(m == NULL) 807 goto final; 808 809 str = ppbus_rstr(ppbus); 810 /* Wait until other side is not transmitting */ 811 if((str & LPIP_SHAKE) || 812 ((ifp->if_flags & IFF_LINK0) && !(str & CLPIP_SHAKE))) { 813 LP_PRINTF("&"); 814 if(++lp->sc_xmit_rtry > LPMAXRTRY) { 815 printf("%s: Too many retries while channel " 816 "busy, going off-line.\n", 817 dev->dv_xname); 818 ppbus_wctr(ppbus, ~IRQENABLE); 819 if_down(ifp); 820 lp->sc_xmit_rtry = 0; 821 } 822 goto final; 823 } 824 lp->sc_xmit_rtry = 0; 825 826 /* Disable interrupt generation */ 827 ppbus_wctr(ppbus, ~IRQENABLE); 828 829 err = 1; 830 831 /* Output packet for Linux/crynwyr compatible protocol */ 832 if(ifp->if_flags & IFF_LINK0) { 833 /* Calculate packet length */ 834 count = 14; /* Ethernet header len */ 835 for(mm = m; mm; mm = mm->m_next) { 836 count += mm->m_len; 837 } 838 839 /* Alert other end to pending packet */ 840 spin = LPMAXSPIN1; 841 ppbus_wdtr(ppbus, 0x08); 842 while((ppbus_rstr(ppbus) & 0x08) == 0) { 843 if (--spin == 0) { 844 goto nend; 845 } 846 } 847 848 if(clpoutbyte(count & 0xFF, LPMAXSPIN1, ppbus)) 849 goto nend; 850 if(clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, ppbus)) 851 goto nend; 852 853 /* Send dummy ethernet header */ 854 chksum = 0; 855 for(i = 0; i < 12; i++) { 856 if(clpoutbyte(i, LPMAXSPIN1, ppbus)) 857 goto nend; 858 chksum += i; 859 } 860 861 if(clpoutbyte(0x08, LPMAXSPIN1, ppbus)) 862 goto nend; 863 if(clpoutbyte(0x00, LPMAXSPIN1, ppbus)) 864 goto nend; 865 chksum += 0x08 + 0x00; /* Add into checksum */ 866 867 mm = m; 868 do { 869 cp = mtod(mm, u_char *); 870 len = mm->m_len; 871 while(len--) { 872 if(clpoutbyte(*cp, LPMAXSPIN2, ppbus)) 873 goto nend; 874 chksum += *cp++; 875 } 876 } while ((mm = mm->m_next)); 877 878 /* Send checksum */ 879 if(clpoutbyte(chksum, LPMAXSPIN2, ppbus)) 880 goto nend; 881 882 /* No errors */ 883 err = 0; 884 /* Go quiescent */ 885 ppbus_wdtr(ppbus, 0); 886 } 887 /* Output packet for FreeBSD compatible protocol */ 888 else { 889 /* We need a sensible value if we abort */ 890 cp = NULL; 891 892 if(lpoutbyte(0x08, LPMAXSPIN1, ppbus)) 893 goto end; 894 if(lpoutbyte(0x00, LPMAXSPIN2, ppbus)) 895 goto end; 896 897 mm = m; 898 do { 899 cp = mtod(mm,u_char *); 900 len = mm->m_len; 901 while(len--) 902 if(lpoutbyte(*cp++, LPMAXSPIN2, ppbus)) 903 goto end; 904 } while ((mm = mm->m_next)); 905 906 /* no errors were encountered */ 907 err = 0; 908 909 end: 910 if(cp) 911 ppbus_wdtr(ppbus, txmitl[*(--cp)] ^ 0x17); 912 else 913 ppbus_wdtr(ppbus, txmitl['\0'] ^ 0x17); 914 } 915 916 nend: 917 /* Re-enable interrupt generation */ 918 ppbus_wctr(ppbus, IRQENABLE); 919 920 if(err) { 921 /* Go quiescent */ 922 ppbus_wdtr(ppbus, 0); 923 924 ifp->if_oerrors++; 925 lp->sc_iferrs++; 926 LP_PRINTF("X"); 927 928 /* Disable interface if there are too many errors */ 929 if(lp->sc_iferrs > LPMAXERRS) { 930 printf("%s: Too many errors, going off-line.\n", 931 dev->dv_xname); 932 ppbus_wctr(ppbus, ~IRQENABLE); 933 if_down(ifp); 934 lp->sc_iferrs = 0; 935 goto final; 936 } 937 } 938 else { 939 /* Dequeue packet on success */ 940 IFQ_DEQUEUE(&ifp->if_snd, m); 941 #if NBPFILTER > 0 942 if(ifp->if_bpf) 943 lptap(ifp, m); 944 #endif 945 ifp->if_opackets++; 946 ifp->if_obytes += m->m_pkthdr.len; 947 m_freem(m); 948 } 949 } 950 951 final: 952 ifp->if_flags &= ~IFF_OACTIVE; 953 return; 954 } 955