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  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD: releng/5.3/sys/dev/ppbus/if_plip.c 135266 2004-09-15 15:14:19Z andre $");
   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
  143 static int volatile lptflag = 1;
  144 #else
  145 static int volatile lptflag = 0;
  146 #endif
  147 
  148 struct lp_data {
  149         struct  ifnet   sc_if;
  150         u_char          *sc_ifbuf;
  151         int             sc_iferrs;
  152 
  153         struct resource *res_irq;
  154 };
  155 
  156 /* Tables for the lp# interface */
  157 static u_char *txmith;
  158 #define txmitl (txmith+(1*LPIPTBLSIZE))
  159 #define trecvh (txmith+(2*LPIPTBLSIZE))
  160 #define trecvl (txmith+(3*LPIPTBLSIZE))
  161 
  162 static 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 */
  168 static int lpinittables(void);
  169 static int lpioctl(struct ifnet *, u_long, caddr_t);
  170 static int lpoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
  171         struct rtentry *);
  172 static void lp_intr(void *);
  173 
  174 #define DEVTOSOFTC(dev) \
  175         ((struct lp_data *)device_get_softc(dev))
  176 #define UNITOSOFTC(unit) \
  177         ((struct lp_data *)devclass_get_softc(lp_devclass, (unit)))
  178 #define UNITODEVICE(unit) \
  179         (devclass_get_device(lp_devclass, (unit)))
  180 
  181 static devclass_t lp_devclass;
  182 
  183 static void
  184 lp_identify(driver_t *driver, device_t parent)
  185 {
  186         device_t dev;
  187 
  188         dev = device_find_child(parent, "plip", 0);
  189         if (!dev)
  190                 BUS_ADD_CHILD(parent, 0, "plip", -1);
  191 }
  192 /*
  193  * lpprobe()
  194  */
  195 static int
  196 lp_probe(device_t dev)
  197 {
  198         device_t ppbus = device_get_parent(dev);
  199         struct lp_data *lp;
  200         int zero = 0;
  201         uintptr_t irq;
  202 
  203         lp = DEVTOSOFTC(dev);
  204 
  205         /* retrieve the ppbus irq */
  206         BUS_READ_IVAR(ppbus, dev, PPBUS_IVAR_IRQ, &irq);
  207 
  208         /* if we haven't interrupts, the probe fails */
  209         if (irq == -1) {
  210                 device_printf(dev, "not an interrupt driven port, failed.\n");
  211                 return (ENXIO);
  212         }
  213 
  214         /* reserve the interrupt resource, expecting irq is available to continue */
  215         lp->res_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &zero, irq, irq, 1, 
  216                                          RF_SHAREABLE);
  217         if (lp->res_irq == 0) {
  218                 device_printf(dev, "cannot reserve interrupt, failed.\n");
  219                 return (ENXIO);
  220         }
  221 
  222         /*
  223          * lp dependent initialisation.
  224          */
  225 
  226         device_set_desc(dev, "PLIP network interface");
  227 
  228         return (0);
  229 }
  230 
  231 static int
  232 lp_attach (device_t dev)
  233 {
  234         struct lp_data *lp = DEVTOSOFTC(dev);
  235         struct ifnet *ifp = &lp->sc_if;
  236 
  237         ifp->if_softc = lp;
  238         if_initname(ifp, device_get_name(dev), device_get_unit(dev));
  239         ifp->if_mtu = LPMTU;
  240         ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST |
  241             IFF_NEEDSGIANT;
  242         ifp->if_ioctl = lpioctl;
  243         ifp->if_output = lpoutput;
  244         ifp->if_type = IFT_PARA;
  245         ifp->if_hdrlen = 0;
  246         ifp->if_addrlen = 0;
  247         ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
  248         if_attach(ifp);
  249 
  250         bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
  251 
  252         return (0);
  253 }
  254 /*
  255  * Build the translation tables for the LPIP (BSD unix) protocol.
  256  * We don't want to calculate these nasties in our tight loop, so we
  257  * precalculate them when we initialize.
  258  */
  259 static int
  260 lpinittables (void)
  261 {
  262     int i;
  263 
  264     if (!txmith)
  265         txmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT);
  266 
  267     if (!txmith)
  268         return 1;
  269 
  270     if (!ctxmith)
  271         ctxmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT);
  272 
  273     if (!ctxmith)
  274         return 1;
  275 
  276     for (i=0; i < LPIPTBLSIZE; i++) {
  277         ctxmith[i] = (i & 0xF0) >> 4;
  278         ctxmitl[i] = 0x10 | (i & 0x0F);
  279         ctrecvh[i] = (i & 0x78) << 1;
  280         ctrecvl[i] = (i & 0x78) >> 3;
  281     }
  282 
  283     for (i=0; i < LPIPTBLSIZE; i++) {
  284         txmith[i] = ((i & 0x80) >> 3) | ((i & 0x70) >> 4) | 0x08;
  285         txmitl[i] = ((i & 0x08) << 1) | (i & 0x07);
  286         trecvh[i] = ((~i) & 0x80) | ((i & 0x38) << 1);
  287         trecvl[i] = (((~i) & 0x80) >> 4) | ((i & 0x38) >> 3);
  288     }
  289 
  290     return 0;
  291 }
  292 
  293 /*
  294  * Process an ioctl request.
  295  */
  296 
  297 static int
  298 lpioctl (struct ifnet *ifp, u_long cmd, caddr_t data)
  299 {
  300     device_t dev = UNITODEVICE(ifp->if_dunit);
  301     device_t ppbus = device_get_parent(dev);
  302     struct lp_data *sc = DEVTOSOFTC(dev);
  303     struct ifaddr *ifa = (struct ifaddr *)data;
  304     struct ifreq *ifr = (struct ifreq *)data;
  305     u_char *ptr;
  306     void *ih;
  307     int error;
  308 
  309     switch (cmd) {
  310 
  311     case SIOCSIFDSTADDR:
  312     case SIOCAIFADDR:
  313     case SIOCSIFADDR:
  314         if (ifa->ifa_addr->sa_family != AF_INET)
  315             return EAFNOSUPPORT;
  316 
  317         ifp->if_flags |= IFF_UP;
  318         /* FALLTHROUGH */
  319     case SIOCSIFFLAGS:
  320         if ((!(ifp->if_flags & IFF_UP)) && (ifp->if_flags & IFF_RUNNING)) {
  321 
  322             ppb_wctr(ppbus, 0x00);
  323             ifp->if_flags &= ~IFF_RUNNING;
  324 
  325             /* IFF_UP is not set, try to release the bus anyway */
  326             ppb_release_bus(ppbus, dev);
  327             break;
  328         }
  329         if (((ifp->if_flags & IFF_UP)) && (!(ifp->if_flags & IFF_RUNNING))) {
  330 
  331             /* XXX
  332              * Should the request be interruptible?
  333              */
  334             if ((error = ppb_request_bus(ppbus, dev, PPB_WAIT|PPB_INTR)))
  335                 return (error);
  336 
  337             /* Now IFF_UP means that we own the bus */
  338 
  339             ppb_set_mode(ppbus, PPB_COMPATIBLE);
  340 
  341             if (lpinittables()) {
  342                 ppb_release_bus(ppbus, dev);
  343                 return ENOBUFS;
  344             }
  345 
  346             sc->sc_ifbuf = malloc(sc->sc_if.if_mtu + MLPIPHDRLEN,
  347                                   M_DEVBUF, M_WAITOK);
  348             if (!sc->sc_ifbuf) {
  349                 ppb_release_bus(ppbus, dev);
  350                 return ENOBUFS;
  351             }
  352 
  353             /* attach our interrupt handler, later detached when the bus is released */
  354             if ((error = BUS_SETUP_INTR(ppbus, dev, sc->res_irq,
  355                                         INTR_TYPE_NET, lp_intr, dev, &ih))) {
  356                 ppb_release_bus(ppbus, dev);
  357                 return (error);
  358             }
  359 
  360             ppb_wctr(ppbus, IRQENABLE);
  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, device_t ppbus)
  412 {
  413         ppb_wdtr(ppbus, ctxmitl[byte]);
  414         while (ppb_rstr(ppbus) & CLPIP_SHAKE)
  415                 if (--spin == 0) {
  416                         return 1;
  417                 }
  418         ppb_wdtr(ppbus, ctxmith[byte]);
  419         while (!(ppb_rstr(ppbus) & CLPIP_SHAKE))
  420                 if (--spin == 0) {
  421                         return 1;
  422                 }
  423         return 0;
  424 }
  425 
  426 static __inline int
  427 clpinbyte (int spin, device_t ppbus)
  428 {
  429         u_char c, cl;
  430 
  431         while((ppb_rstr(ppbus) & CLPIP_SHAKE))
  432             if(!--spin) {
  433                 return -1;
  434             }
  435         cl = ppb_rstr(ppbus);
  436         ppb_wdtr(ppbus, 0x10);
  437 
  438         while(!(ppb_rstr(ppbus) & CLPIP_SHAKE))
  439             if(!--spin) {
  440                 return -1;
  441             }
  442         c = ppb_rstr(ppbus);
  443         ppb_wdtr(ppbus, 0x00);
  444 
  445         return (ctrecvl[cl] | ctrecvh[c]);
  446 }
  447 
  448 static void
  449 lptap(struct ifnet *ifp, struct mbuf *m)
  450 {
  451         u_int32_t af = AF_INET;
  452         BPF_MTAP2(ifp, &af, sizeof(af), m);
  453 }
  454 
  455 static void
  456 lp_intr (void *arg)
  457 {
  458         device_t dev = (device_t)arg;
  459         device_t ppbus = device_get_parent(dev);
  460         struct lp_data *sc = DEVTOSOFTC(dev);
  461         int len, s, j;
  462         u_char *bp;
  463         u_char c, cl;
  464         struct mbuf *top;
  465 
  466         s = splhigh();
  467 
  468         if (sc->sc_if.if_flags & IFF_LINK0) {
  469 
  470             /* Ack. the request */
  471             ppb_wdtr(ppbus, 0x01);
  472 
  473             /* Get the packet length */
  474             j = clpinbyte(LPMAXSPIN2, ppbus);
  475             if (j == -1)
  476                 goto err;
  477             len = j;
  478             j = clpinbyte(LPMAXSPIN2, ppbus);
  479             if (j == -1)
  480                 goto err;
  481             len = len + (j << 8);
  482             if (len > sc->sc_if.if_mtu + MLPIPHDRLEN)
  483                 goto err;
  484 
  485             bp  = sc->sc_ifbuf;
  486         
  487             while (len--) {
  488                 j = clpinbyte(LPMAXSPIN2, ppbus);
  489                 if (j == -1) {
  490                     goto err;
  491                 }
  492                 *bp++ = j;
  493             }
  494             /* Get and ignore checksum */
  495             j = clpinbyte(LPMAXSPIN2, ppbus);
  496             if (j == -1) {
  497                 goto err;
  498             }
  499 
  500             len = bp - sc->sc_ifbuf;
  501             if (len <= CLPIPHDRLEN)
  502                 goto err;
  503 
  504             sc->sc_iferrs = 0;
  505 
  506             len -= CLPIPHDRLEN;
  507             sc->sc_if.if_ipackets++;
  508             sc->sc_if.if_ibytes += len;
  509             top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, &sc->sc_if, 0);
  510             if (top) {
  511                 if (sc->sc_if.if_bpf)
  512                     lptap(&sc->sc_if, top);
  513                 netisr_queue(NETISR_IP, top);   /* mbuf is free'd on failure. */
  514             }
  515             goto done;
  516         }
  517         while ((ppb_rstr(ppbus) & LPIP_SHAKE)) {
  518             len = sc->sc_if.if_mtu + LPIPHDRLEN;
  519             bp  = sc->sc_ifbuf;
  520             while (len--) {
  521 
  522                 cl = ppb_rstr(ppbus);
  523                 ppb_wdtr(ppbus, 8);
  524 
  525                 j = LPMAXSPIN2;
  526                 while((ppb_rstr(ppbus) & LPIP_SHAKE))
  527                     if(!--j) goto err;
  528 
  529                 c = ppb_rstr(ppbus);
  530                 ppb_wdtr(ppbus, 0);
  531 
  532                 *bp++= trecvh[cl] | trecvl[c];
  533 
  534                 j = LPMAXSPIN2;
  535                 while (!((cl=ppb_rstr(ppbus)) & LPIP_SHAKE)) {
  536                     if (cl != c &&
  537                         (((cl = ppb_rstr(ppbus)) ^ 0xb8) & 0xf8) ==
  538                           (c & 0xf8))
  539                         goto end;
  540                     if (!--j) goto err;
  541                 }
  542             }
  543 
  544         end:
  545             len = bp - sc->sc_ifbuf;
  546             if (len <= LPIPHDRLEN)
  547                 goto err;
  548 
  549             sc->sc_iferrs = 0;
  550 
  551             len -= LPIPHDRLEN;
  552             sc->sc_if.if_ipackets++;
  553             sc->sc_if.if_ibytes += len;
  554             top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, &sc->sc_if, 0);
  555             if (top) {
  556                 if (sc->sc_if.if_bpf)
  557                     lptap(&sc->sc_if, top);
  558                 netisr_queue(NETISR_IP, top);   /* mbuf is free'd on failure. */
  559             }
  560         }
  561         goto done;
  562 
  563     err:
  564         ppb_wdtr(ppbus, 0);
  565         lprintf("R");
  566         sc->sc_if.if_ierrors++;
  567         sc->sc_iferrs++;
  568 
  569         /*
  570          * We are not able to send receive anything for now,
  571          * so stop wasting our time
  572          */
  573         if (sc->sc_iferrs > LPMAXERRS) {
  574             printf("lp%d: Too many errors, Going off-line.\n", device_get_unit(dev));
  575             ppb_wctr(ppbus, 0x00);
  576             sc->sc_if.if_flags &= ~IFF_RUNNING;
  577             sc->sc_iferrs=0;
  578         }
  579 
  580     done:
  581         splx(s);
  582         return;
  583 }
  584 
  585 static __inline int
  586 lpoutbyte (u_char byte, int spin, device_t ppbus)
  587 {
  588     ppb_wdtr(ppbus, txmith[byte]);
  589     while (!(ppb_rstr(ppbus) & LPIP_SHAKE))
  590         if (--spin == 0)
  591                 return 1;
  592     ppb_wdtr(ppbus, txmitl[byte]);
  593     while (ppb_rstr(ppbus) & LPIP_SHAKE)
  594         if (--spin == 0)
  595                 return 1;
  596     return 0;
  597 }
  598 
  599 static int
  600 lpoutput (struct ifnet *ifp, struct mbuf *m,
  601           struct sockaddr *dst, struct rtentry *rt)
  602 {
  603     device_t dev = UNITODEVICE(ifp->if_dunit);
  604     device_t ppbus = device_get_parent(dev);
  605     int s, err;
  606     struct mbuf *mm;
  607     u_char *cp = "\0\0";
  608     u_char chksum = 0;
  609     int count = 0;
  610     int i, len, spin;
  611 
  612     /* We need a sensible value if we abort */
  613     cp++;
  614     ifp->if_flags |= IFF_RUNNING;
  615 
  616     err = 1;                    /* assume we're aborting because of an error */
  617 
  618     s = splhigh();
  619 
  620     /* Suspend (on laptops) or receive-errors might have taken us offline */
  621     ppb_wctr(ppbus, IRQENABLE);
  622 
  623     if (ifp->if_flags & IFF_LINK0) {
  624 
  625         if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) {
  626             lprintf("&");
  627             lp_intr(dev);
  628         }
  629 
  630         /* Alert other end to pending packet */
  631         spin = LPMAXSPIN1;
  632         ppb_wdtr(ppbus, 0x08);
  633         while ((ppb_rstr(ppbus) & 0x08) == 0)
  634                 if (--spin == 0) {
  635                         goto nend;
  636                 }
  637 
  638         /* Calculate length of packet, then send that */
  639 
  640         count += 14;            /* Ethernet header len */
  641 
  642         mm = m;
  643         for (mm = m; mm; mm = mm->m_next) {
  644                 count += mm->m_len;
  645         }
  646         if (clpoutbyte(count & 0xFF, LPMAXSPIN1, ppbus))
  647                 goto nend;
  648         if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, ppbus))
  649                 goto nend;
  650 
  651         /* Send dummy ethernet header */
  652         for (i = 0; i < 12; i++) {
  653                 if (clpoutbyte(i, LPMAXSPIN1, ppbus))
  654                         goto nend;
  655                 chksum += i;
  656         }
  657 
  658         if (clpoutbyte(0x08, LPMAXSPIN1, ppbus))
  659                 goto nend;
  660         if (clpoutbyte(0x00, LPMAXSPIN1, ppbus))
  661                 goto nend;
  662         chksum += 0x08 + 0x00;          /* Add into checksum */
  663 
  664         mm = m;
  665         do {
  666                 cp = mtod(mm, u_char *);
  667                 len = mm->m_len;
  668                 while (len--) {
  669                         chksum += *cp;
  670                         if (clpoutbyte(*cp++, LPMAXSPIN2, ppbus))
  671                                 goto nend;
  672                 }
  673         } while ((mm = mm->m_next));
  674 
  675         /* Send checksum */
  676         if (clpoutbyte(chksum, LPMAXSPIN2, ppbus))
  677                 goto nend;
  678 
  679         /* Go quiescent */
  680         ppb_wdtr(ppbus, 0);
  681 
  682         err = 0;                        /* No errors */
  683 
  684         nend:
  685         if (err)  {                             /* if we didn't timeout... */
  686                 ifp->if_oerrors++;
  687                 lprintf("X");
  688         } else {
  689                 ifp->if_opackets++;
  690                 ifp->if_obytes += m->m_pkthdr.len;
  691                 if (ifp->if_bpf)
  692                     lptap(ifp, m);
  693         }
  694 
  695         m_freem(m);
  696 
  697         if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) {
  698                 lprintf("^");
  699                 lp_intr(dev);
  700         }
  701         (void) splx(s);
  702         return 0;
  703     }
  704 
  705     if (ppb_rstr(ppbus) & LPIP_SHAKE) {
  706         lprintf("&");
  707         lp_intr(dev);
  708     }
  709 
  710     if (lpoutbyte(0x08, LPMAXSPIN1, ppbus))
  711         goto end;
  712     if (lpoutbyte(0x00, LPMAXSPIN2, ppbus))
  713         goto end;
  714 
  715     mm = m;
  716     do {
  717         cp = mtod(mm,u_char *);
  718         len = mm->m_len;
  719         while (len--)
  720             if (lpoutbyte(*cp++, LPMAXSPIN2, ppbus))
  721                 goto end;
  722     } while ((mm = mm->m_next));
  723 
  724     err = 0;                            /* no errors were encountered */
  725 
  726     end:
  727     --cp;
  728     ppb_wdtr(ppbus, txmitl[*cp] ^ 0x17);
  729 
  730     if (err)  {                         /* if we didn't timeout... */
  731         ifp->if_oerrors++;
  732         lprintf("X");
  733     } else {
  734         ifp->if_opackets++;
  735         ifp->if_obytes += m->m_pkthdr.len;
  736         if (ifp->if_bpf)
  737             lptap(ifp, m);
  738     }
  739 
  740     m_freem(m);
  741 
  742     if (ppb_rstr(ppbus) & LPIP_SHAKE) {
  743         lprintf("^");
  744         lp_intr(dev);
  745     }
  746 
  747     (void) splx(s);
  748     return 0;
  749 }
  750 
  751 static device_method_t lp_methods[] = {
  752         /* device interface */
  753         DEVMETHOD(device_identify,      lp_identify),
  754         DEVMETHOD(device_probe,         lp_probe),
  755         DEVMETHOD(device_attach,        lp_attach),
  756 
  757         { 0, 0 }
  758 };
  759 
  760 static driver_t lp_driver = {
  761   "plip",
  762   lp_methods,
  763   sizeof(struct lp_data),
  764 };
  765 
  766 DRIVER_MODULE(plip, ppbus, lp_driver, lp_devclass, 0, 0);

Cache object: 923c8bf2d21c2f8af115ec426f843f11


[ 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.