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