if_plip.c revision 55939
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: head/sys/dev/ppbus/if_plip.c 55939 2000-01-14 00:18:06Z nsouch $ 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@freebsd.org> 75 */ 76 77/* 78 * Update for ppbus, PLIP support only - Nicolas Souchu 79 */ 80#include "plip.h" 81 82#if NPLIP > 0 83 84#include "opt_plip.h" 85 86#include <sys/param.h> 87#include <sys/systm.h> 88#include <sys/module.h> 89#include <sys/bus.h> 90#include <sys/conf.h> 91#include <sys/mbuf.h> 92#include <sys/socket.h> 93#include <sys/sockio.h> 94#include <sys/kernel.h> 95#include <sys/malloc.h> 96 97#include <machine/clock.h> 98#include <machine/bus.h> 99#include <machine/resource.h> 100#include <sys/rman.h> 101 102#include <net/if.h> 103#include <net/if_types.h> 104#include <net/netisr.h> 105 106#include <netinet/in.h> 107#include <netinet/in_var.h> 108 109#include <net/bpf.h> 110 111#include <dev/ppbus/ppbconf.h> 112#include "ppbus_if.h" 113#include <dev/ppbus/ppbio.h> 114 115#ifndef LPMTU /* MTU for the lp# interfaces */ 116#define LPMTU 1500 117#endif 118 119#ifndef LPMAXSPIN1 /* DELAY factor for the lp# interfaces */ 120#define LPMAXSPIN1 8000 /* Spinning for remote intr to happen */ 121#endif 122 123#ifndef LPMAXSPIN2 /* DELAY factor for the lp# interfaces */ 124#define LPMAXSPIN2 500 /* Spinning for remote handshake to happen */ 125#endif 126 127#ifndef LPMAXERRS /* Max errors before !RUNNING */ 128#define LPMAXERRS 100 129#endif 130 131#define CLPIPHDRLEN 14 /* We send dummy ethernet addresses (two) + packet type in front of packet */ 132#define CLPIP_SHAKE 0x80 /* This bit toggles between nibble reception */ 133#define MLPIPHDRLEN CLPIPHDRLEN 134 135#define LPIPHDRLEN 2 /* We send 0x08, 0x00 in front of packet */ 136#define LPIP_SHAKE 0x40 /* This bit toggles between nibble reception */ 137#if !defined(MLPIPHDRLEN) || LPIPHDRLEN > MLPIPHDRLEN 138#define MLPIPHDRLEN LPIPHDRLEN 139#endif 140 141#define LPIPTBLSIZE 256 /* Size of octet translation table */ 142 143#define lprintf if (lptflag) printf 144 145#ifdef PLIP_DEBUG 146static int volatile lptflag = 1; 147#else 148static int volatile lptflag = 0; 149#endif 150 151struct lp_data { 152 unsigned short lp_unit; 153 154 struct ifnet sc_if; 155 u_char *sc_ifbuf; 156 int sc_iferrs; 157 158 struct resource *res_irq; 159}; 160 161/* Tables for the lp# interface */ 162static u_char *txmith; 163#define txmitl (txmith+(1*LPIPTBLSIZE)) 164#define trecvh (txmith+(2*LPIPTBLSIZE)) 165#define trecvl (txmith+(3*LPIPTBLSIZE)) 166 167static u_char *ctxmith; 168#define ctxmitl (ctxmith+(1*LPIPTBLSIZE)) 169#define ctrecvh (ctxmith+(2*LPIPTBLSIZE)) 170#define ctrecvl (ctxmith+(3*LPIPTBLSIZE)) 171 172/* Functions for the lp# interface */ 173static int lp_probe(device_t dev); 174static int lp_attach(device_t dev); 175 176static int lpinittables(void); 177static int lpioctl(struct ifnet *, u_long, caddr_t); 178static int lpoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 179 struct rtentry *); 180static void lp_intr(void *); 181 182#define DEVTOSOFTC(dev) \ 183 ((struct lp_data *)device_get_softc(dev)) 184#define UNITOSOFTC(unit) \ 185 ((struct lp_data *)devclass_get_softc(lp_devclass, (unit))) 186#define UNITODEVICE(unit) \ 187 (devclass_get_device(lp_devclass, (unit))) 188 189static devclass_t lp_devclass; 190 191static device_method_t lp_methods[] = { 192 /* device interface */ 193 DEVMETHOD(device_probe, lp_probe), 194 DEVMETHOD(device_attach, lp_attach), 195 196 { 0, 0 } 197}; 198 199static driver_t lp_driver = { 200 "plip", 201 lp_methods, 202 sizeof(struct lp_data), 203}; 204 205/* 206 * lpprobe() 207 */ 208static int 209lp_probe(device_t dev) 210{ 211 device_t ppbus = device_get_parent(dev); 212 struct lp_data *lp; 213 int irq, zero = 0; 214 215 lp = DEVTOSOFTC(dev); 216 bzero(lp, sizeof(struct lp_data)); 217 218 /* retrieve the ppbus irq */ 219 BUS_READ_IVAR(ppbus, dev, PPBUS_IVAR_IRQ, &irq); 220 221 /* if we haven't interrupts, the probe fails */ 222 if (irq == -1) { 223 device_printf(dev, "not an interrupt driven port, failed.\n"); 224 return (ENXIO); 225 } 226 227 /* reserve the interrupt resource, expecting irq is available to continue */ 228 lp->res_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &zero, irq, irq, 1, 229 RF_SHAREABLE); 230 if (lp->res_irq == 0) { 231 device_printf(dev, "cannot reserve interrupt, failed.\n"); 232 return (ENXIO); 233 } 234 235 /* 236 * lp dependent initialisation. 237 */ 238 lp->lp_unit = device_get_unit(dev); 239 240 device_set_desc(dev, "PLIP network interface"); 241 242 return (0); 243} 244 245static int 246lp_attach (device_t dev) 247{ 248 struct lp_data *lp = DEVTOSOFTC(dev); 249 struct ifnet *ifp = &lp->sc_if; 250 251 ifp->if_softc = lp; 252 ifp->if_name = "lp"; 253 ifp->if_unit = device_get_unit(dev); 254 ifp->if_mtu = LPMTU; 255 ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST; 256 ifp->if_ioctl = lpioctl; 257 ifp->if_output = lpoutput; 258 ifp->if_type = IFT_PARA; 259 ifp->if_hdrlen = 0; 260 ifp->if_addrlen = 0; 261 ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 262 if_attach(ifp); 263 264 bpfattach(ifp, DLT_NULL, sizeof(u_int32_t)); 265 266 return (0); 267} 268/* 269 * Build the translation tables for the LPIP (BSD unix) protocol. 270 * We don't want to calculate these nasties in our tight loop, so we 271 * precalculate them when we initialize. 272 */ 273static int 274lpinittables (void) 275{ 276 int i; 277 278 if (!txmith) 279 txmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT); 280 281 if (!txmith) 282 return 1; 283 284 if (!ctxmith) 285 ctxmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT); 286 287 if (!ctxmith) 288 return 1; 289 290 for (i=0; i < LPIPTBLSIZE; i++) { 291 ctxmith[i] = (i & 0xF0) >> 4; 292 ctxmitl[i] = 0x10 | (i & 0x0F); 293 ctrecvh[i] = (i & 0x78) << 1; 294 ctrecvl[i] = (i & 0x78) >> 3; 295 } 296 297 for (i=0; i < LPIPTBLSIZE; i++) { 298 txmith[i] = ((i & 0x80) >> 3) | ((i & 0x70) >> 4) | 0x08; 299 txmitl[i] = ((i & 0x08) << 1) | (i & 0x07); 300 trecvh[i] = ((~i) & 0x80) | ((i & 0x38) << 1); 301 trecvl[i] = (((~i) & 0x80) >> 4) | ((i & 0x38) >> 3); 302 } 303 304 return 0; 305} 306 307/* 308 * Process an ioctl request. 309 */ 310 311static int 312lpioctl (struct ifnet *ifp, u_long cmd, caddr_t data) 313{ 314 device_t dev = UNITODEVICE(ifp->if_unit); 315 device_t ppbus = device_get_parent(dev); 316 struct lp_data *sc = DEVTOSOFTC(dev); 317 struct ifaddr *ifa = (struct ifaddr *)data; 318 struct ifreq *ifr = (struct ifreq *)data; 319 u_char *ptr; 320 void *ih; 321 int error; 322 323 switch (cmd) { 324 325 case SIOCSIFDSTADDR: 326 case SIOCAIFADDR: 327 case SIOCSIFADDR: 328 if (ifa->ifa_addr->sa_family != AF_INET) 329 return EAFNOSUPPORT; 330 331 ifp->if_flags |= IFF_UP; 332 /* FALLTHROUGH */ 333 case SIOCSIFFLAGS: 334 if ((!(ifp->if_flags & IFF_UP)) && (ifp->if_flags & IFF_RUNNING)) { 335 336 ppb_wctr(ppbus, 0x00); 337 ifp->if_flags &= ~IFF_RUNNING; 338 339 /* IFF_UP is not set, try to release the bus anyway */ 340 ppb_release_bus(ppbus, dev); 341 break; 342 } 343 if (((ifp->if_flags & IFF_UP)) && (!(ifp->if_flags & IFF_RUNNING))) { 344 345 /* XXX 346 * Should the request be interruptible? 347 */ 348 if ((error = ppb_request_bus(ppbus, dev, PPB_WAIT|PPB_INTR))) 349 return (error); 350 351 /* Now IFF_UP means that we own the bus */ 352 353 ppb_set_mode(ppbus, PPB_COMPATIBLE); 354 355 if (lpinittables()) { 356 ppb_release_bus(ppbus, dev); 357 return ENOBUFS; 358 } 359 360 sc->sc_ifbuf = malloc(sc->sc_if.if_mtu + MLPIPHDRLEN, 361 M_DEVBUF, M_WAITOK); 362 if (!sc->sc_ifbuf) { 363 ppb_release_bus(ppbus, dev); 364 return ENOBUFS; 365 } 366 367 /* attach our interrupt handler, later detached when the bus is released */ 368 if ((error = BUS_SETUP_INTR(ppbus, dev, sc->res_irq, 369 INTR_TYPE_NET, lp_intr, dev, &ih))) { 370 ppb_release_bus(ppbus, dev); 371 return (error); 372 } 373 374 ppb_wctr(ppbus, IRQENABLE); 375 ifp->if_flags |= IFF_RUNNING; 376 } 377 break; 378 379 case SIOCSIFMTU: 380 ptr = sc->sc_ifbuf; 381 sc->sc_ifbuf = malloc(ifr->ifr_mtu+MLPIPHDRLEN, M_DEVBUF, M_NOWAIT); 382 if (!sc->sc_ifbuf) { 383 sc->sc_ifbuf = ptr; 384 return ENOBUFS; 385 } 386 if (ptr) 387 free(ptr,M_DEVBUF); 388 sc->sc_if.if_mtu = ifr->ifr_mtu; 389 break; 390 391 case SIOCGIFMTU: 392 ifr->ifr_mtu = sc->sc_if.if_mtu; 393 break; 394 395 case SIOCADDMULTI: 396 case SIOCDELMULTI: 397 if (ifr == 0) { 398 return EAFNOSUPPORT; /* XXX */ 399 } 400 switch (ifr->ifr_addr.sa_family) { 401 402 case AF_INET: 403 break; 404 405 default: 406 return EAFNOSUPPORT; 407 } 408 break; 409 410 case SIOCGIFMEDIA: 411 /* 412 * No ifmedia support at this stage; maybe use it 413 * in future for eg. protocol selection. 414 */ 415 return EINVAL; 416 417 default: 418 lprintf("LP:ioctl(0x%lx)\n", cmd); 419 return EINVAL; 420 } 421 return 0; 422} 423 424static __inline int 425clpoutbyte (u_char byte, int spin, device_t ppbus) 426{ 427 ppb_wdtr(ppbus, ctxmitl[byte]); 428 while (ppb_rstr(ppbus) & CLPIP_SHAKE) 429 if (--spin == 0) { 430 return 1; 431 } 432 ppb_wdtr(ppbus, ctxmith[byte]); 433 while (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) 434 if (--spin == 0) { 435 return 1; 436 } 437 return 0; 438} 439 440static __inline int 441clpinbyte (int spin, device_t ppbus) 442{ 443 u_char c, cl; 444 445 while((ppb_rstr(ppbus) & CLPIP_SHAKE)) 446 if(!--spin) { 447 return -1; 448 } 449 cl = ppb_rstr(ppbus); 450 ppb_wdtr(ppbus, 0x10); 451 452 while(!(ppb_rstr(ppbus) & CLPIP_SHAKE)) 453 if(!--spin) { 454 return -1; 455 } 456 c = ppb_rstr(ppbus); 457 ppb_wdtr(ppbus, 0x00); 458 459 return (ctrecvl[cl] | ctrecvh[c]); 460} 461 462static void 463lptap(struct ifnet *ifp, struct mbuf *m) 464{ 465 /* 466 * Send a packet through bpf. We need to prepend the address family 467 * as a four byte field. Cons up a dummy header to pacify bpf. This 468 * is safe because bpf will only read from the mbuf (i.e., it won't 469 * try to free it or keep a pointer to it). 470 */ 471 u_int32_t af = AF_INET; 472 struct mbuf m0; 473 474 m0.m_next = m; 475 m0.m_len = sizeof(u_int32_t); 476 m0.m_data = (char *)⁡ 477 bpf_mtap(ifp, &m0); 478} 479 480static void 481lp_intr (void *arg) 482{ 483 device_t dev = (device_t)arg; 484 device_t ppbus = device_get_parent(dev); 485 struct lp_data *sc = DEVTOSOFTC(dev); 486 int len, s, j; 487 u_char *bp; 488 u_char c, cl; 489 struct mbuf *top; 490 491 s = splhigh(); 492 493 if (sc->sc_if.if_flags & IFF_LINK0) { 494 495 /* Ack. the request */ 496 ppb_wdtr(ppbus, 0x01); 497 498 /* Get the packet length */ 499 j = clpinbyte(LPMAXSPIN2, ppbus); 500 if (j == -1) 501 goto err; 502 len = j; 503 j = clpinbyte(LPMAXSPIN2, ppbus); 504 if (j == -1) 505 goto err; 506 len = len + (j << 8); 507 if (len > sc->sc_if.if_mtu + MLPIPHDRLEN) 508 goto err; 509 510 bp = sc->sc_ifbuf; 511 512 while (len--) { 513 j = clpinbyte(LPMAXSPIN2, ppbus); 514 if (j == -1) { 515 goto err; 516 } 517 *bp++ = j; 518 } 519 /* Get and ignore checksum */ 520 j = clpinbyte(LPMAXSPIN2, ppbus); 521 if (j == -1) { 522 goto err; 523 } 524 525 len = bp - sc->sc_ifbuf; 526 if (len <= CLPIPHDRLEN) 527 goto err; 528 529 sc->sc_iferrs = 0; 530 531 if (IF_QFULL(&ipintrq)) { 532 lprintf("DROP"); 533 IF_DROP(&ipintrq); 534 goto done; 535 } 536 len -= CLPIPHDRLEN; 537 sc->sc_if.if_ipackets++; 538 sc->sc_if.if_ibytes += len; 539 top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, &sc->sc_if, 0); 540 if (top) { 541 if (sc->sc_if.if_bpf) 542 lptap(&sc->sc_if, top); 543 IF_ENQUEUE(&ipintrq, top); 544 schednetisr(NETISR_IP); 545 } 546 goto done; 547 } 548 while ((ppb_rstr(ppbus) & LPIP_SHAKE)) { 549 len = sc->sc_if.if_mtu + LPIPHDRLEN; 550 bp = sc->sc_ifbuf; 551 while (len--) { 552 553 cl = ppb_rstr(ppbus); 554 ppb_wdtr(ppbus, 8); 555 556 j = LPMAXSPIN2; 557 while((ppb_rstr(ppbus) & LPIP_SHAKE)) 558 if(!--j) goto err; 559 560 c = ppb_rstr(ppbus); 561 ppb_wdtr(ppbus, 0); 562 563 *bp++= trecvh[cl] | trecvl[c]; 564 565 j = LPMAXSPIN2; 566 while (!((cl=ppb_rstr(ppbus)) & LPIP_SHAKE)) { 567 if (cl != c && 568 (((cl = ppb_rstr(ppbus)) ^ 0xb8) & 0xf8) == 569 (c & 0xf8)) 570 goto end; 571 if (!--j) goto err; 572 } 573 } 574 575 end: 576 len = bp - sc->sc_ifbuf; 577 if (len <= LPIPHDRLEN) 578 goto err; 579 580 sc->sc_iferrs = 0; 581 582 if (IF_QFULL(&ipintrq)) { 583 lprintf("DROP"); 584 IF_DROP(&ipintrq); 585 goto done; 586 } 587 len -= LPIPHDRLEN; 588 sc->sc_if.if_ipackets++; 589 sc->sc_if.if_ibytes += len; 590 top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, &sc->sc_if, 0); 591 if (top) { 592 if (sc->sc_if.if_bpf) 593 lptap(&sc->sc_if, top); 594 IF_ENQUEUE(&ipintrq, top); 595 schednetisr(NETISR_IP); 596 } 597 } 598 goto done; 599 600 err: 601 ppb_wdtr(ppbus, 0); 602 lprintf("R"); 603 sc->sc_if.if_ierrors++; 604 sc->sc_iferrs++; 605 606 /* 607 * We are not able to send receive anything for now, 608 * so stop wasting our time 609 */ 610 if (sc->sc_iferrs > LPMAXERRS) { 611 printf("lp%d: Too many errors, Going off-line.\n", device_get_unit(dev)); 612 ppb_wctr(ppbus, 0x00); 613 sc->sc_if.if_flags &= ~IFF_RUNNING; 614 sc->sc_iferrs=0; 615 } 616 617 done: 618 splx(s); 619 return; 620} 621 622static __inline int 623lpoutbyte (u_char byte, int spin, device_t ppbus) 624{ 625 ppb_wdtr(ppbus, txmith[byte]); 626 while (!(ppb_rstr(ppbus) & LPIP_SHAKE)) 627 if (--spin == 0) 628 return 1; 629 ppb_wdtr(ppbus, txmitl[byte]); 630 while (ppb_rstr(ppbus) & LPIP_SHAKE) 631 if (--spin == 0) 632 return 1; 633 return 0; 634} 635 636static int 637lpoutput (struct ifnet *ifp, struct mbuf *m, 638 struct sockaddr *dst, struct rtentry *rt) 639{ 640 device_t dev = UNITODEVICE(ifp->if_unit); 641 device_t ppbus = device_get_parent(dev); 642 int s, err; 643 struct mbuf *mm; 644 u_char *cp = "\0\0"; 645 u_char chksum = 0; 646 int count = 0; 647 int i, len, spin; 648 649 /* We need a sensible value if we abort */ 650 cp++; 651 ifp->if_flags |= IFF_RUNNING; 652 653 err = 1; /* assume we're aborting because of an error */ 654 655 s = splhigh(); 656 657 /* Suspend (on laptops) or receive-errors might have taken us offline */ 658 ppb_wctr(ppbus, IRQENABLE); 659 660 if (ifp->if_flags & IFF_LINK0) { 661 662 if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) { 663 lprintf("&"); 664 lp_intr(dev); 665 } 666 667 /* Alert other end to pending packet */ 668 spin = LPMAXSPIN1; 669 ppb_wdtr(ppbus, 0x08); 670 while ((ppb_rstr(ppbus) & 0x08) == 0) 671 if (--spin == 0) { 672 goto nend; 673 } 674 675 /* Calculate length of packet, then send that */ 676 677 count += 14; /* Ethernet header len */ 678 679 mm = m; 680 for (mm = m; mm; mm = mm->m_next) { 681 count += mm->m_len; 682 } 683 if (clpoutbyte(count & 0xFF, LPMAXSPIN1, ppbus)) 684 goto nend; 685 if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, ppbus)) 686 goto nend; 687 688 /* Send dummy ethernet header */ 689 for (i = 0; i < 12; i++) { 690 if (clpoutbyte(i, LPMAXSPIN1, ppbus)) 691 goto nend; 692 chksum += i; 693 } 694 695 if (clpoutbyte(0x08, LPMAXSPIN1, ppbus)) 696 goto nend; 697 if (clpoutbyte(0x00, LPMAXSPIN1, ppbus)) 698 goto nend; 699 chksum += 0x08 + 0x00; /* Add into checksum */ 700 701 mm = m; 702 do { 703 cp = mtod(mm, u_char *); 704 len = mm->m_len; 705 while (len--) { 706 chksum += *cp; 707 if (clpoutbyte(*cp++, LPMAXSPIN2, ppbus)) 708 goto nend; 709 } 710 } while ((mm = mm->m_next)); 711 712 /* Send checksum */ 713 if (clpoutbyte(chksum, LPMAXSPIN2, ppbus)) 714 goto nend; 715 716 /* Go quiescent */ 717 ppb_wdtr(ppbus, 0); 718 719 err = 0; /* No errors */ 720 721 nend: 722 if (err) { /* if we didn't timeout... */ 723 ifp->if_oerrors++; 724 lprintf("X"); 725 } else { 726 ifp->if_opackets++; 727 ifp->if_obytes += m->m_pkthdr.len; 728 if (ifp->if_bpf) 729 lptap(ifp, m); 730 } 731 732 m_freem(m); 733 734 if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) { 735 lprintf("^"); 736 lp_intr(dev); 737 } 738 (void) splx(s); 739 return 0; 740 } 741 742 if (ppb_rstr(ppbus) & LPIP_SHAKE) { 743 lprintf("&"); 744 lp_intr(dev); 745 } 746 747 if (lpoutbyte(0x08, LPMAXSPIN1, ppbus)) 748 goto end; 749 if (lpoutbyte(0x00, LPMAXSPIN2, ppbus)) 750 goto end; 751 752 mm = m; 753 do { 754 cp = mtod(mm,u_char *); 755 len = mm->m_len; 756 while (len--) 757 if (lpoutbyte(*cp++, LPMAXSPIN2, ppbus)) 758 goto end; 759 } while ((mm = mm->m_next)); 760 761 err = 0; /* no errors were encountered */ 762 763 end: 764 --cp; 765 ppb_wdtr(ppbus, txmitl[*cp] ^ 0x17); 766 767 if (err) { /* if we didn't timeout... */ 768 ifp->if_oerrors++; 769 lprintf("X"); 770 } else { 771 ifp->if_opackets++; 772 ifp->if_obytes += m->m_pkthdr.len; 773 if (ifp->if_bpf) 774 lptap(ifp, m); 775 } 776 777 m_freem(m); 778 779 if (ppb_rstr(ppbus) & LPIP_SHAKE) { 780 lprintf("^"); 781 lp_intr(dev); 782 } 783 784 (void) splx(s); 785 return 0; 786} 787 788DRIVER_MODULE(plip, ppbus, lp_driver, lp_devclass, 0, 0); 789 790#endif /* NPLIP > 0 */ 791