1/* $NetBSD: if_plip.c,v 1.38 2022/09/04 15:59:08 rjs 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.38 2022/09/04 15:59:08 rjs 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 a 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 90#include <sys/systm.h> 91#include <sys/param.h> 92#include <sys/proc.h> 93#include <sys/types.h> 94#include <sys/device.h> 95#include <sys/ioctl.h> 96#include <sys/malloc.h> 97#include <sys/mbuf.h> 98 99#include <net/if.h> 100#include <net/if_types.h> 101 102#include <sys/time.h> 103#include <net/bpf.h> 104 105#ifdef INET 106#include <netinet/in.h> 107#include <netinet/in_systm.h> 108#include <netinet/in_var.h> 109#include <netinet/ip.h> 110#else 111#error Cannot config lp/plip without inet 112#endif 113 114#include <dev/ppbus/ppbus_base.h> 115#include <dev/ppbus/ppbus_device.h> 116#include <dev/ppbus/ppbus_io.h> 117#include <dev/ppbus/ppbus_var.h> 118 119#include <machine/types.h> 120#include <sys/intr.h> 121 122#ifndef LPMTU /* MTU for the lp# interfaces */ 123#define LPMTU 1500 124#endif 125 126#ifndef LPMAXSPIN1 /* DELAY factor for the lp# interfaces */ 127#define LPMAXSPIN1 8000 /* Spinning for remote intr to happen */ 128#endif 129 130#ifndef LPMAXSPIN2 /* DELAY factor for the lp# interfaces */ 131#define LPMAXSPIN2 500 /* Spinning for remote handshake to happen */ 132#endif 133 134#ifndef LPMAXERRS /* Max errors before !RUNNING */ 135#define LPMAXERRS 100 136#endif 137 138#ifndef LPMAXRTRY 139#define LPMAXRTRY 100 /* If channel busy, retry LPMAXRTRY 140 consecutive times */ 141#endif 142 143#define CLPIPHDRLEN 14 /* We send dummy ethernet addresses (two) + packet type in front of packet */ 144#define CLPIP_SHAKE 0x80 /* This bit toggles between nibble reception */ 145#define MLPIPHDRLEN CLPIPHDRLEN 146 147#define LPIPHDRLEN 2 /* We send 0x08, 0x00 in front of packet */ 148#define LPIP_SHAKE 0x40 /* This bit toggles between nibble reception */ 149#if !defined(MLPIPHDRLEN) || LPIPHDRLEN > MLPIPHDRLEN 150#define MLPIPHDRLEN LPIPHDRLEN 151#endif 152 153#define LPIPTBLSIZE 256 /* Size of octet translation table */ 154 155#define LP_PRINTF if (lpflag) printf 156 157#ifdef PLIP_DEBUG 158static int volatile lpflag = 1; 159#else 160static int volatile lpflag = 0; 161#endif 162 163/* Tx/Rsv tables for the lp interface */ 164static u_char *txmith; 165#define txmitl (txmith+(1*LPIPTBLSIZE)) 166#define trecvh (txmith+(2*LPIPTBLSIZE)) 167#define trecvl (txmith+(3*LPIPTBLSIZE)) 168static u_char *ctxmith; 169#define ctxmitl (ctxmith+(1*LPIPTBLSIZE)) 170#define ctrecvh (ctxmith+(2*LPIPTBLSIZE)) 171#define ctrecvl (ctxmith+(3*LPIPTBLSIZE)) 172static uint16_t lp_count = 0; 173 174/* Autoconf functions */ 175static int lp_probe(device_t, cfdata_t, void *); 176static void lp_attach(device_t, device_t, void *); 177static int lp_detach(device_t, int); 178 179/* Soft config data */ 180struct lp_softc { 181 struct ppbus_device_softc ppbus_dev; 182 struct ifnet sc_if; 183 u_char *sc_ifbuf; 184 unsigned short sc_iferrs; 185 unsigned short sc_xmit_rtry; 186 u_int8_t sc_dev_ok; /* Zero means ok */ 187}; 188 189/* Autoconf structure */ 190CFATTACH_DECL_NEW(plip, sizeof(struct lp_softc), lp_probe, lp_attach, lp_detach, 191 NULL); 192 193/* Functions for the lp interface */ 194static void lpinittables(void); 195static void lpfreetables(void); 196static int lpioctl(struct ifnet *, u_long, void *); 197static int lpoutput(struct ifnet *, struct mbuf *, const struct sockaddr *, 198 const struct rtentry *); 199static void lpstart(struct ifnet *); 200static void lp_intr(void *); 201 202 203static int 204lp_probe(device_t parent, cfdata_t match, void *aux) 205{ 206 struct ppbus_attach_args * args = aux; 207 208 /* Fail if ppbus is not interrupt capable */ 209 if (args->capabilities & PPBUS_HAS_INTR) 210 return 1; 211 212 printf("%s(%s): not an interrupt-driven port.\n", __func__, 213 device_xname(parent)); 214 return 0; 215} 216 217static void 218lp_attach(device_t parent, device_t self, void *aux) 219{ 220 struct lp_softc * lp = device_private(self); 221 struct ifnet * ifp = &lp->sc_if; 222 223 lp->ppbus_dev.sc_dev = self; 224 lp->sc_dev_ok = 0; 225 lp->sc_ifbuf = NULL; 226 lp->sc_iferrs = 0; 227 lp->sc_xmit_rtry = 0; 228 229 ifp->if_softc = lp; 230 strlcpy(ifp->if_xname, device_xname(self), IFNAMSIZ); 231 ifp->if_mtu = LPMTU; 232 ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST; 233 ifp->if_ioctl = lpioctl; 234 ifp->if_output = lpoutput; 235 ifp->if_start = lpstart; 236 ifp->if_type = IFT_PARA; 237 ifp->if_hdrlen = 0; 238 ifp->if_addrlen = 0; 239 ifp->if_dlt = DLT_NULL; 240 IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 241 IFQ_SET_READY(&ifp->if_snd); 242 if_attach(ifp); 243 if_alloc_sadl(ifp); 244 245 bpf_attach(ifp, DLT_NULL, sizeof(u_int32_t)); 246 247 if (lp_count++ == 0) 248 lpinittables(); 249 printf("\n"); 250} 251 252static int 253lp_detach(device_t self, int flags) 254{ 255 int error = 0; 256 struct lp_softc * lp = device_private(self); 257 device_t ppbus = device_parent(self); 258 259 if (lp->sc_dev_ok) { 260 if (!(flags & DETACH_QUIET)) 261 LP_PRINTF("%s(%s): device not properly attached! " 262 "Skipping detach....\n", __func__, 263 device_xname(self)); 264 return error; 265 } 266 267 /* If interface is up, bring it down and release ppbus */ 268 if (lp->sc_if.if_flags & IFF_RUNNING) { 269 ppbus_wctr(ppbus, 0x00); 270 if_detach(&lp->sc_if); 271 error = ppbus_remove_handler(ppbus, lp_intr); 272 if (error) { 273 if (!(flags & DETACH_QUIET)) 274 LP_PRINTF("%s(%s): unable to remove interrupt " 275 "callback.\n", __func__, 276 device_xname(self)); 277 if (!(flags & DETACH_FORCE)) 278 return error; 279 } 280 error = ppbus_release_bus(ppbus, self, 0, 0); 281 if (error) { 282 if (!(flags & DETACH_QUIET)) 283 LP_PRINTF("%s(%s): error releasing bus %s.\n", 284 __func__, device_xname(self), 285 device_xname(ppbus)); 286 if (!(flags & DETACH_FORCE)) 287 return error; 288 } 289 } 290 291 if (lp->sc_ifbuf) 292 free(lp->sc_ifbuf, M_DEVBUF); 293 294 if (--lp_count == 0) 295 lpfreetables(); 296 return error; 297} 298 299/* 300 * Build the translation tables for the LPIP (BSD unix) protocol. 301 * We don't want to calculate these nasties in our tight loop, so we 302 * precalculate them when we initialize. 303 */ 304static void 305lpinittables(void) 306{ 307 int i; 308 309 if (!txmith) 310 txmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_WAITOK); 311 312 if (!ctxmith) 313 ctxmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_WAITOK); 314 315 for (i = 0; i < LPIPTBLSIZE; i++) { 316 ctxmith[i] = (i & 0xF0) >> 4; 317 ctxmitl[i] = 0x10 | (i & 0x0F); 318 ctrecvh[i] = (i & 0x78) << 1; 319 ctrecvl[i] = (i & 0x78) >> 3; 320 } 321 322 for (i = 0; i < LPIPTBLSIZE; i++) { 323 txmith[i] = ((i & 0x80) >> 3) | ((i & 0x70) >> 4) | 0x08; 324 txmitl[i] = ((i & 0x08) << 1) | (i & 0x07); 325 trecvh[i] = ((~i) & 0x80) | ((i & 0x38) << 1); 326 trecvl[i] = (((~i) & 0x80) >> 4) | ((i & 0x38) >> 3); 327 } 328} 329 330/* Free translation tables */ 331static void 332lpfreetables(void) 333{ 334 if (txmith) 335 free(txmith, M_DEVBUF); 336 if (ctxmith) 337 free(ctxmith, M_DEVBUF); 338 txmith = ctxmith = NULL; 339} 340 341 342/* Process an ioctl request. */ 343static int 344lpioctl(struct ifnet *ifp, u_long cmd, void *data) 345{ 346 struct lp_softc * sc = ifp->if_softc; 347 device_t dev = sc->ppbus_dev.sc_dev; 348 device_t ppbus = device_parent(dev); 349 struct ifaddr * ifa = (struct ifaddr *)data; 350 struct ifreq * ifr = (struct ifreq *)data; 351 u_char * ptr; 352 int error, s; 353 354 error = 0; 355 s = splnet(); 356 357 if (sc->sc_dev_ok) { 358 LP_PRINTF("%s(%s): device not properly attached!", __func__, 359 device_xname(dev)); 360 error = ENODEV; 361 goto end; 362 } 363 364 switch (cmd) { 365 366 case SIOCSIFDSTADDR: 367 if (ifa->ifa_addr->sa_family != AF_INET) 368 error = EAFNOSUPPORT; 369 break; 370 371 case SIOCINITIFADDR: 372 if (ifa->ifa_addr->sa_family != AF_INET) { 373 error = EAFNOSUPPORT; 374 break; 375 } 376 ifp->if_flags |= IFF_UP; 377 /* FALLTHROUGH */ 378 case SIOCSIFFLAGS: 379 if (cmd == SIOCSIFFLAGS) { 380 if ((error = ifioctl_common(ifp, cmd, data)) != 0) 381 break; 382 } 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 device_xname(dev)); 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_WAITOK); 403 } 404 405 ppbus_wctr(ppbus, IRQENABLE); 406 ifp->if_flags |= IFF_RUNNING; 407 } 408 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_RUNNING) { 409 ppbus_remove_handler(ppbus, lp_intr); 410 error = ppbus_release_bus(ppbus, dev, 0, 0); 411 ifp->if_flags &= ~IFF_RUNNING; 412 } 413 /* Go quiescent */ 414 ppbus_wdtr(ppbus, 0); 415 break; 416 417 case SIOCSIFMTU: 418 if (sc->sc_if.if_mtu == ifr->ifr_mtu) 419 break; 420 ptr = sc->sc_ifbuf; 421 sc->sc_ifbuf = malloc(ifr->ifr_mtu + MLPIPHDRLEN, M_DEVBUF, 422 M_WAITOK); 423 if (ptr) 424 free(ptr,M_DEVBUF); 425 /*FALLTHROUGH*/ 426 case SIOCGIFMTU: 427 if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET) 428 error = 0; 429 break; 430 431 case SIOCADDMULTI: 432 case SIOCDELMULTI: 433 if (ifr == NULL) { 434 error = EAFNOSUPPORT; /* XXX */ 435 break; 436 } 437 switch (ifreq_getaddr(cmd, ifr)->sa_family) { 438 case AF_INET: 439 break; 440 default: 441 splx(s); 442 return EAFNOSUPPORT; 443 } 444 break; 445 446 case SIOCGIFMEDIA: 447 /* 448 * No ifmedia support at this stage; maybe use it 449 * in future for eg. protocol selection. 450 */ 451 default: 452 LP_PRINTF("LP:ioctl(0x%lx)\n", cmd); 453 error = ifioctl_common(ifp, cmd, data); 454 } 455 456end: 457 splx(s); 458 return error; 459} 460 461static inline int 462clpoutbyte(u_char byte, int spin, device_t ppbus) 463{ 464 int s = spin; 465 ppbus_wdtr(ppbus, ctxmitl[byte]); 466 while (ppbus_rstr(ppbus) & CLPIP_SHAKE) { 467 if (--s == 0) { 468 return 1; 469 } 470 } 471 s = spin; 472 ppbus_wdtr(ppbus, ctxmith[byte]); 473 while (!(ppbus_rstr(ppbus) & CLPIP_SHAKE)) { 474 if (--s == 0) { 475 return 1; 476 } 477 } 478 return 0; 479} 480 481static inline int 482clpinbyte(int spin, device_t ppbus) 483{ 484 u_char c, cl; 485 int s = spin; 486 487 while (ppbus_rstr(ppbus) & CLPIP_SHAKE) { 488 if (!--s) { 489 return -1; 490 } 491 } 492 cl = ppbus_rstr(ppbus); 493 ppbus_wdtr(ppbus, 0x10); 494 495 s = spin; 496 while (!(ppbus_rstr(ppbus) & CLPIP_SHAKE)) { 497 if (!--s) { 498 return -1; 499 } 500 } 501 c = ppbus_rstr(ppbus); 502 ppbus_wdtr(ppbus, 0x00); 503 504 return (ctrecvl[cl] | ctrecvh[c]); 505} 506 507static void 508lptap(struct ifnet *ifp, struct mbuf *m, u_int direction) 509{ 510 /* 511 * Send a packet through bpf. We need to prepend the address family 512 * as a four byte field. Cons up a dummy header to pacify bpf. This 513 * is safe because bpf will only read from the mbuf (i.e., it won't 514 * try to free it or keep a pointer to it). 515 */ 516 u_int32_t af = AF_INET; 517 struct mbuf m0; 518 519 m0.m_type = MT_DATA; 520 m0.m_next = m; 521 m0.m_nextpkt = NULL; 522 m0.m_owner = NULL; 523 m0.m_len = sizeof(u_int32_t); 524 m0.m_data = (char *)⁡ 525 m0.m_flags = 0; 526 bpf_mtap(ifp, &m0, direction); 527} 528 529/* Soft interrupt handler called by hardware interrupt handler */ 530static void 531lp_intr(void *arg) 532{ 533 device_t dev = (device_t)arg; 534 device_t ppbus = device_parent(dev); 535 struct lp_softc * sc = device_private(dev); 536 struct ifnet * ifp = &sc->sc_if; 537 struct mbuf *top; 538 int len, s, j; 539 u_char *bp; 540 u_char c, cl; 541 542 s = splnet(); 543 544 /* Do nothing if device not properly attached */ 545 if (sc->sc_dev_ok) { 546 LP_PRINTF("%s(%s): device not properly attached!", __func__, 547 device_xname(dev)); 548 goto done; 549 } 550 551 /* Do nothing if interface is not up */ 552 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 553 goto done; 554 555 /* If other side is no longer transmitting, do nothing */ 556 if (!(ppbus_rstr(ppbus) & LPIP_SHAKE)) 557 goto done; 558 559 /* Disable interrupts until we finish */ 560 ppbus_wctr(ppbus, ~IRQENABLE); 561 562 top = NULL; 563 bp = sc->sc_ifbuf; 564 /* Linux/crynwyr protocol receiving */ 565 if (ifp->if_flags & IFF_LINK0) { 566 /* Ack. the request */ 567 ppbus_wdtr(ppbus, 0x01); 568 569 /* Get the packet length */ 570 j = clpinbyte(LPMAXSPIN2, ppbus); 571 if (j == -1) 572 goto err; 573 len = j; 574 j = clpinbyte(LPMAXSPIN2, ppbus); 575 if (j == -1) 576 goto err; 577 len = len + (j << 8); 578 if (len > ifp->if_mtu + MLPIPHDRLEN) 579 goto err; 580 581 while (len--) { 582 j = clpinbyte(LPMAXSPIN2, ppbus); 583 if (j == -1) { 584 goto err; 585 } 586 *bp++ = j; 587 } 588 /* Get and ignore checksum */ 589 j = clpinbyte(LPMAXSPIN2, ppbus); 590 if (j == -1) { 591 goto err; 592 } 593 594 /* Return to idle state */ 595 ppbus_wdtr(ppbus, 0); 596 len = bp - sc->sc_ifbuf; 597 if (len <= CLPIPHDRLEN) 598 goto err; 599 len -= CLPIPHDRLEN; 600 top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, ifp); 601 } 602 /* FreeBSD protocol receiving */ 603 else { 604 len = ifp->if_mtu + LPIPHDRLEN; 605 while (len--) { 606 cl = ppbus_rstr(ppbus); 607 ppbus_wdtr(ppbus, 0x08); 608 609 j = LPMAXSPIN2; 610 while ((ppbus_rstr(ppbus) & LPIP_SHAKE)) { 611 if (!--j) 612 goto err; 613 } 614 615 c = ppbus_rstr(ppbus); 616 ppbus_wdtr(ppbus, 0); 617 618 *bp++= trecvh[cl] | trecvl[c]; 619 620 j = LPMAXSPIN2; 621 while (!((cl = ppbus_rstr(ppbus)) & LPIP_SHAKE)) { 622 if (cl != c && 623 (((cl = ppbus_rstr(ppbus)) ^ 0xb8) & 624 0xf8) == (c & 0xf8)) 625 goto end; 626 if (!--j) 627 goto err; 628 } 629 } 630 631end: 632 len = bp - sc->sc_ifbuf; 633 if (len <= LPIPHDRLEN) 634 goto err; 635 len -= LPIPHDRLEN; 636 top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, ifp); 637 } 638 639 if (top == NULL) { 640 if_statinc(ifp, if_iqdrops); 641 goto err; 642 } 643 if (ifp->if_bpf) { 644 lptap(ifp, top, BPF_D_IN); 645 } 646 if (__predict_false(!pktq_enqueue(ip_pktq, top, 0))) { 647 if_statinc(ifp, if_iqdrops); 648 m_freem(top); 649 goto err; 650 } 651 if_statinc(ifp, if_ipackets); 652 if_statadd(ifp, if_ibytes, len); 653 sc->sc_iferrs = 0; 654 655 goto done; 656 657err: 658 /* Return to idle state */ 659 ppbus_wdtr(ppbus, 0); 660 if_statinc(ifp, if_ierrors); 661 sc->sc_iferrs++; 662 LP_PRINTF("R"); 663 /* Disable interface if there are too many errors */ 664 if (sc->sc_iferrs > LPMAXERRS) { 665 aprint_error_dev(dev, "Too many consecutive errors, going off-line.\n"); 666 ppbus_wctr(ppbus, ~IRQENABLE); 667 if_down(ifp); 668 sc->sc_iferrs = 0; 669 } 670 671done: 672 /* Re-enable interrupts */ 673 ppbus_wctr(ppbus, IRQENABLE); 674 /* If interface is not active, send some packets */ 675 if ((ifp->if_flags & IFF_OACTIVE) == 0) 676 lpstart(ifp); 677 splx(s); 678 return; 679} 680 681static inline int 682lpoutbyte(u_char byte, int spin, device_t ppbus) 683{ 684 int s = spin; 685 ppbus_wdtr(ppbus, txmith[byte]); 686 while (!(ppbus_rstr(ppbus) & LPIP_SHAKE)) { 687 if (--s == 0) 688 return 1; 689 } 690 s = spin; 691 ppbus_wdtr(ppbus, txmitl[byte]); 692 while (ppbus_rstr(ppbus) & LPIP_SHAKE) { 693 if (--s == 0) 694 return 1; 695 } 696 return 0; 697} 698 699/* Queue a packet for delivery */ 700static int 701lpoutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 702 const struct rtentry *rt) 703{ 704 struct lp_softc * sc = ifp->if_softc; 705 device_t dev = sc->ppbus_dev.sc_dev; 706 device_t ppbus = device_parent(dev); 707 int err; 708 int s; 709 710 s = splnet(); 711 712 if (sc->sc_dev_ok) { 713 LP_PRINTF("%s(%s): device not properly attached!", __func__, 714 device_xname(dev)); 715 err = ENODEV; 716 goto endoutput; 717 } 718 719 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 720 err = ENETDOWN; 721 goto endoutput; 722 } 723 724 /* Only support INET */ 725 if (dst->sa_family != AF_INET) { 726 LP_PRINTF("%s: af%d not supported\n", ifp->if_xname, 727 dst->sa_family); 728 if_statinc(ifp, if_noproto); 729 err = EAFNOSUPPORT; 730 goto endoutput; 731 } 732 733 IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family); 734 IFQ_ENQUEUE(&ifp->if_snd, m, err); 735 if (err == 0) { 736 if ((ifp->if_flags & IFF_OACTIVE) == 0) 737 lpstart(ifp); 738 } else { 739 if_statinc(ifp, if_oerrors); 740 sc->sc_iferrs++; 741 LP_PRINTF("Q"); 742 743 /* Disable interface if there are too many errors */ 744 if (sc->sc_iferrs > LPMAXERRS) { 745 aprint_error_dev(dev, "Too many errors, going off-line.\n"); 746 ppbus_wctr(ppbus, ~IRQENABLE); 747 if_down(ifp); 748 sc->sc_iferrs = 0; 749 } 750 } 751 752endoutput: 753 if ((err != 0) && (err != ENOBUFS)) 754 m_freem(m); 755 splx(s); 756 return err; 757} 758 759/* Send routine: send packets over PLIP cable. Call at splnet(). */ 760void 761lpstart(struct ifnet * ifp) 762{ 763 struct lp_softc * lp = ifp->if_softc; 764 device_t dev = lp->ppbus_dev.sc_dev; 765 device_t ppbus = device_parent(dev); 766 struct mbuf * mm; 767 struct mbuf * m; 768 u_char * cp; 769 int err, i, len, spin, count; 770 u_char str, chksum; 771 772 if (lp->sc_dev_ok) { 773 LP_PRINTF("%s(%s): device not properly attached!", __func__, 774 device_xname(dev)); 775 return; 776 } 777 778 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 779 return; 780 } 781 782 ifp->if_flags |= IFF_OACTIVE; 783 784 /* Go quiescent */ 785 ppbus_wdtr(ppbus, 0); 786 787 /* Output loop */ 788 for (;;) { 789 /* Check if there are packets to send */ 790 if (IFQ_IS_EMPTY(&ifp->if_snd)) { 791 goto final; 792 } 793 /* Try to send a packet, dequeue it later if successful */ 794 IFQ_POLL(&ifp->if_snd, m); 795 if (m == NULL) 796 goto final; 797 798 str = ppbus_rstr(ppbus); 799 /* Wait until other side is not transmitting */ 800 if ((str & LPIP_SHAKE) || 801 ((ifp->if_flags & IFF_LINK0) && !(str & CLPIP_SHAKE))) { 802 LP_PRINTF("&"); 803 if (++lp->sc_xmit_rtry > LPMAXRTRY) { 804 aprint_error_dev(dev, "Too many retries while channel " 805 "busy, going off-line.\n"); 806 ppbus_wctr(ppbus, ~IRQENABLE); 807 if_down(ifp); 808 lp->sc_xmit_rtry = 0; 809 } 810 goto final; 811 } 812 lp->sc_xmit_rtry = 0; 813 814 /* Disable interrupt generation */ 815 ppbus_wctr(ppbus, ~IRQENABLE); 816 817 err = 1; 818 819 /* Output packet for Linux/crynwyr compatible protocol */ 820 if (ifp->if_flags & IFF_LINK0) { 821 /* Calculate packet length */ 822 count = 14; /* Ethernet header len */ 823 for (mm = m; mm; mm = mm->m_next) { 824 count += mm->m_len; 825 } 826 827 /* Alert other end to pending packet */ 828 spin = LPMAXSPIN1; 829 ppbus_wdtr(ppbus, 0x08); 830 while ((ppbus_rstr(ppbus) & 0x08) == 0) { 831 if (--spin == 0) { 832 goto nend; 833 } 834 } 835 836 if (clpoutbyte(count & 0xFF, LPMAXSPIN1, ppbus)) 837 goto nend; 838 if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, ppbus)) 839 goto nend; 840 841 /* Send dummy ethernet header */ 842 chksum = 0; 843 for (i = 0; i < 12; i++) { 844 if (clpoutbyte(i, LPMAXSPIN1, ppbus)) 845 goto nend; 846 chksum += i; 847 } 848 849 if (clpoutbyte(0x08, LPMAXSPIN1, ppbus)) 850 goto nend; 851 if (clpoutbyte(0x00, LPMAXSPIN1, ppbus)) 852 goto nend; 853 chksum += 0x08 + 0x00; /* Add into checksum */ 854 855 mm = m; 856 do { 857 cp = mtod(mm, u_char *); 858 len = mm->m_len; 859 while (len--) { 860 if (clpoutbyte(*cp, LPMAXSPIN2, ppbus)) 861 goto nend; 862 chksum += *cp++; 863 } 864 } while ((mm = mm->m_next)); 865 866 /* Send checksum */ 867 if (clpoutbyte(chksum, LPMAXSPIN2, ppbus)) 868 goto nend; 869 870 /* No errors */ 871 err = 0; 872 /* Go quiescent */ 873 ppbus_wdtr(ppbus, 0); 874 } 875 /* Output packet for FreeBSD compatible protocol */ 876 else { 877 /* We need a sensible value if we abort */ 878 cp = NULL; 879 880 if (lpoutbyte(0x08, LPMAXSPIN1, ppbus)) 881 goto end; 882 if (lpoutbyte(0x00, LPMAXSPIN2, ppbus)) 883 goto end; 884 885 mm = m; 886 do { 887 cp = mtod(mm,u_char *); 888 len = mm->m_len; 889 while (len--) 890 if (lpoutbyte(*cp++, LPMAXSPIN2, ppbus)) 891 goto end; 892 } while ((mm = mm->m_next)); 893 894 /* no errors were encountered */ 895 err = 0; 896 897end: 898 if (cp) 899 ppbus_wdtr(ppbus, txmitl[*(--cp)] ^ 0x17); 900 else 901 ppbus_wdtr(ppbus, txmitl['\0'] ^ 0x17); 902 } 903 904nend: 905 /* Re-enable interrupt generation */ 906 ppbus_wctr(ppbus, IRQENABLE); 907 908 if (err) { 909 /* Go quiescent */ 910 ppbus_wdtr(ppbus, 0); 911 912 if_statinc(ifp, if_oerrors); 913 lp->sc_iferrs++; 914 LP_PRINTF("X"); 915 916 /* Disable interface if there are too many errors */ 917 if (lp->sc_iferrs > LPMAXERRS) { 918 aprint_error_dev(dev, "Too many errors, going off-line.\n"); 919 ppbus_wctr(ppbus, ~IRQENABLE); 920 if_down(ifp); 921 lp->sc_iferrs = 0; 922 goto final; 923 } 924 } else { 925 /* Dequeue packet on success */ 926 IFQ_DEQUEUE(&ifp->if_snd, m); 927 if(ifp->if_bpf) 928 lptap(ifp, m, BPF_D_OUT); 929 if_statinc(ifp, if_opackets); 930 if_statadd(ifp, if_obytes, m->m_pkthdr.len); 931 m_freem(m); 932 } 933 } 934 935final: 936 ifp->if_flags &= ~IFF_OACTIVE; 937 return; 938} 939