The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ppbus/if_plip.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 3de5fa4515f043a7e4b26f4a44088493


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.