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$");
   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_ifp;
  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", -1);
  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;
  236 
  237         ifp = lp->sc_ifp = if_alloc(IFT_PARA);
  238         if (ifp == NULL) {
  239                 return (ENOSPC);
  240         }
  241 
  242         ifp->if_softc = lp;
  243         if_initname(ifp, device_get_name(dev), device_get_unit(dev));
  244         ifp->if_mtu = LPMTU;
  245         ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST |
  246             IFF_NEEDSGIANT;
  247         ifp->if_ioctl = lpioctl;
  248         ifp->if_output = lpoutput;
  249         ifp->if_hdrlen = 0;
  250         ifp->if_addrlen = 0;
  251         ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
  252         if_attach(ifp);
  253 
  254         bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
  255 
  256         return (0);
  257 }
  258 /*
  259  * Build the translation tables for the LPIP (BSD unix) protocol.
  260  * We don't want to calculate these nasties in our tight loop, so we
  261  * precalculate them when we initialize.
  262  */
  263 static int
  264 lpinittables (void)
  265 {
  266     int i;
  267 
  268     if (!txmith)
  269         txmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT);
  270 
  271     if (!txmith)
  272         return 1;
  273 
  274     if (!ctxmith)
  275         ctxmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT);
  276 
  277     if (!ctxmith)
  278         return 1;
  279 
  280     for (i=0; i < LPIPTBLSIZE; i++) {
  281         ctxmith[i] = (i & 0xF0) >> 4;
  282         ctxmitl[i] = 0x10 | (i & 0x0F);
  283         ctrecvh[i] = (i & 0x78) << 1;
  284         ctrecvl[i] = (i & 0x78) >> 3;
  285     }
  286 
  287     for (i=0; i < LPIPTBLSIZE; i++) {
  288         txmith[i] = ((i & 0x80) >> 3) | ((i & 0x70) >> 4) | 0x08;
  289         txmitl[i] = ((i & 0x08) << 1) | (i & 0x07);
  290         trecvh[i] = ((~i) & 0x80) | ((i & 0x38) << 1);
  291         trecvl[i] = (((~i) & 0x80) >> 4) | ((i & 0x38) >> 3);
  292     }
  293 
  294     return 0;
  295 }
  296 
  297 /*
  298  * Process an ioctl request.
  299  */
  300 
  301 static int
  302 lpioctl (struct ifnet *ifp, u_long cmd, caddr_t data)
  303 {
  304     device_t dev = UNITODEVICE(ifp->if_dunit);
  305     device_t ppbus = device_get_parent(dev);
  306     struct lp_data *sc = DEVTOSOFTC(dev);
  307     struct ifaddr *ifa = (struct ifaddr *)data;
  308     struct ifreq *ifr = (struct ifreq *)data;
  309     u_char *ptr;
  310     void *ih;
  311     int error;
  312 
  313     switch (cmd) {
  314 
  315     case SIOCSIFDSTADDR:
  316     case SIOCAIFADDR:
  317     case SIOCSIFADDR:
  318         if (ifa->ifa_addr->sa_family != AF_INET)
  319             return EAFNOSUPPORT;
  320 
  321         ifp->if_flags |= IFF_UP;
  322         /* FALLTHROUGH */
  323     case SIOCSIFFLAGS:
  324         if ((!(ifp->if_flags & IFF_UP)) &&
  325           (ifp->if_drv_flags & IFF_DRV_RUNNING)) {
  326 
  327             ppb_wctr(ppbus, 0x00);
  328             ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
  329 
  330             /* IFF_UP is not set, try to release the bus anyway */
  331             ppb_release_bus(ppbus, dev);
  332             break;
  333         }
  334         if (((ifp->if_flags & IFF_UP)) &&
  335           (!(ifp->if_drv_flags & IFF_DRV_RUNNING))) {
  336 
  337             /* XXX
  338              * Should the request be interruptible?
  339              */
  340             if ((error = ppb_request_bus(ppbus, dev, PPB_WAIT|PPB_INTR)))
  341                 return (error);
  342 
  343             /* Now IFF_UP means that we own the bus */
  344 
  345             ppb_set_mode(ppbus, PPB_COMPATIBLE);
  346 
  347             if (lpinittables()) {
  348                 ppb_release_bus(ppbus, dev);
  349                 return ENOBUFS;
  350             }
  351 
  352             sc->sc_ifbuf = malloc(sc->sc_ifp->if_mtu + MLPIPHDRLEN,
  353                                   M_DEVBUF, M_WAITOK);
  354             if (!sc->sc_ifbuf) {
  355                 ppb_release_bus(ppbus, dev);
  356                 return ENOBUFS;
  357             }
  358 
  359             /* attach our interrupt handler, later detached when the bus is released */
  360             if ((error = bus_setup_intr(dev, sc->res_irq,
  361                                         INTR_TYPE_NET, NULL, lp_intr, dev, &ih))) {
  362                 ppb_release_bus(ppbus, dev);
  363                 return (error);
  364             }
  365 
  366             ppb_wctr(ppbus, IRQENABLE);
  367             ifp->if_drv_flags |= IFF_DRV_RUNNING;
  368         }
  369         break;
  370 
  371     case SIOCSIFMTU:
  372         ptr = sc->sc_ifbuf;
  373         sc->sc_ifbuf = malloc(ifr->ifr_mtu+MLPIPHDRLEN, M_DEVBUF, M_NOWAIT);
  374         if (!sc->sc_ifbuf) {
  375             sc->sc_ifbuf = ptr;
  376             return ENOBUFS;
  377         }
  378         if (ptr)
  379             free(ptr,M_DEVBUF);
  380         sc->sc_ifp->if_mtu = ifr->ifr_mtu;
  381         break;
  382 
  383     case SIOCGIFMTU:
  384         ifr->ifr_mtu = sc->sc_ifp->if_mtu;
  385         break;
  386 
  387     case SIOCADDMULTI:
  388     case SIOCDELMULTI:
  389         if (ifr == 0) {
  390             return EAFNOSUPPORT;                /* XXX */
  391         }
  392         switch (ifr->ifr_addr.sa_family) {
  393 
  394         case AF_INET:
  395             break;
  396 
  397         default:
  398             return EAFNOSUPPORT;
  399         }
  400         break;
  401 
  402     case SIOCGIFMEDIA:
  403         /*
  404          * No ifmedia support at this stage; maybe use it
  405          * in future for eg. protocol selection.
  406          */
  407         return EINVAL;
  408 
  409     default:
  410         lprintf("LP:ioctl(0x%lx)\n", cmd);
  411         return EINVAL;
  412     }
  413     return 0;
  414 }
  415 
  416 static __inline int
  417 clpoutbyte (u_char byte, int spin, device_t ppbus)
  418 {
  419         ppb_wdtr(ppbus, ctxmitl[byte]);
  420         while (ppb_rstr(ppbus) & CLPIP_SHAKE)
  421                 if (--spin == 0) {
  422                         return 1;
  423                 }
  424         ppb_wdtr(ppbus, ctxmith[byte]);
  425         while (!(ppb_rstr(ppbus) & CLPIP_SHAKE))
  426                 if (--spin == 0) {
  427                         return 1;
  428                 }
  429         return 0;
  430 }
  431 
  432 static __inline int
  433 clpinbyte (int spin, device_t ppbus)
  434 {
  435         u_char c, cl;
  436 
  437         while((ppb_rstr(ppbus) & CLPIP_SHAKE))
  438             if(!--spin) {
  439                 return -1;
  440             }
  441         cl = ppb_rstr(ppbus);
  442         ppb_wdtr(ppbus, 0x10);
  443 
  444         while(!(ppb_rstr(ppbus) & CLPIP_SHAKE))
  445             if(!--spin) {
  446                 return -1;
  447             }
  448         c = ppb_rstr(ppbus);
  449         ppb_wdtr(ppbus, 0x00);
  450 
  451         return (ctrecvl[cl] | ctrecvh[c]);
  452 }
  453 
  454 static void
  455 lptap(struct ifnet *ifp, struct mbuf *m)
  456 {
  457         u_int32_t af = AF_INET;
  458         bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m);
  459 }
  460 
  461 static void
  462 lp_intr (void *arg)
  463 {
  464         device_t dev = (device_t)arg;
  465         device_t ppbus = device_get_parent(dev);
  466         struct lp_data *sc = DEVTOSOFTC(dev);
  467         int len, s, j;
  468         u_char *bp;
  469         u_char c, cl;
  470         struct mbuf *top;
  471 
  472         s = splhigh();
  473 
  474         if (sc->sc_ifp->if_flags & IFF_LINK0) {
  475 
  476             /* Ack. the request */
  477             ppb_wdtr(ppbus, 0x01);
  478 
  479             /* Get the packet length */
  480             j = clpinbyte(LPMAXSPIN2, ppbus);
  481             if (j == -1)
  482                 goto err;
  483             len = j;
  484             j = clpinbyte(LPMAXSPIN2, ppbus);
  485             if (j == -1)
  486                 goto err;
  487             len = len + (j << 8);
  488             if (len > sc->sc_ifp->if_mtu + MLPIPHDRLEN)
  489                 goto err;
  490 
  491             bp  = sc->sc_ifbuf;
  492         
  493             while (len--) {
  494                 j = clpinbyte(LPMAXSPIN2, ppbus);
  495                 if (j == -1) {
  496                     goto err;
  497                 }
  498                 *bp++ = j;
  499             }
  500             /* Get and ignore checksum */
  501             j = clpinbyte(LPMAXSPIN2, ppbus);
  502             if (j == -1) {
  503                 goto err;
  504             }
  505 
  506             len = bp - sc->sc_ifbuf;
  507             if (len <= CLPIPHDRLEN)
  508                 goto err;
  509 
  510             sc->sc_iferrs = 0;
  511 
  512             len -= CLPIPHDRLEN;
  513             sc->sc_ifp->if_ipackets++;
  514             sc->sc_ifp->if_ibytes += len;
  515             top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, sc->sc_ifp, 0);
  516             if (top) {
  517                 if (bpf_peers_present(sc->sc_ifp->if_bpf))
  518                     lptap(sc->sc_ifp, top);
  519                 netisr_queue(NETISR_IP, top);   /* mbuf is free'd on failure. */
  520             }
  521             goto done;
  522         }
  523         while ((ppb_rstr(ppbus) & LPIP_SHAKE)) {
  524             len = sc->sc_ifp->if_mtu + LPIPHDRLEN;
  525             bp  = sc->sc_ifbuf;
  526             while (len--) {
  527 
  528                 cl = ppb_rstr(ppbus);
  529                 ppb_wdtr(ppbus, 8);
  530 
  531                 j = LPMAXSPIN2;
  532                 while((ppb_rstr(ppbus) & LPIP_SHAKE))
  533                     if(!--j) goto err;
  534 
  535                 c = ppb_rstr(ppbus);
  536                 ppb_wdtr(ppbus, 0);
  537 
  538                 *bp++= trecvh[cl] | trecvl[c];
  539 
  540                 j = LPMAXSPIN2;
  541                 while (!((cl=ppb_rstr(ppbus)) & LPIP_SHAKE)) {
  542                     if (cl != c &&
  543                         (((cl = ppb_rstr(ppbus)) ^ 0xb8) & 0xf8) ==
  544                           (c & 0xf8))
  545                         goto end;
  546                     if (!--j) goto err;
  547                 }
  548             }
  549 
  550         end:
  551             len = bp - sc->sc_ifbuf;
  552             if (len <= LPIPHDRLEN)
  553                 goto err;
  554 
  555             sc->sc_iferrs = 0;
  556 
  557             len -= LPIPHDRLEN;
  558             sc->sc_ifp->if_ipackets++;
  559             sc->sc_ifp->if_ibytes += len;
  560             top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, sc->sc_ifp, 0);
  561             if (top) {
  562                 if (bpf_peers_present(sc->sc_ifp->if_bpf))
  563                     lptap(sc->sc_ifp, top);
  564                 netisr_queue(NETISR_IP, top);   /* mbuf is free'd on failure. */
  565             }
  566         }
  567         goto done;
  568 
  569     err:
  570         ppb_wdtr(ppbus, 0);
  571         lprintf("R");
  572         sc->sc_ifp->if_ierrors++;
  573         sc->sc_iferrs++;
  574 
  575         /*
  576          * We are not able to send receive anything for now,
  577          * so stop wasting our time
  578          */
  579         if (sc->sc_iferrs > LPMAXERRS) {
  580             printf("lp%d: Too many errors, Going off-line.\n", device_get_unit(dev));
  581             ppb_wctr(ppbus, 0x00);
  582             sc->sc_ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
  583             sc->sc_iferrs=0;
  584         }
  585 
  586     done:
  587         splx(s);
  588         return;
  589 }
  590 
  591 static __inline int
  592 lpoutbyte (u_char byte, int spin, device_t ppbus)
  593 {
  594     ppb_wdtr(ppbus, txmith[byte]);
  595     while (!(ppb_rstr(ppbus) & LPIP_SHAKE))
  596         if (--spin == 0)
  597                 return 1;
  598     ppb_wdtr(ppbus, txmitl[byte]);
  599     while (ppb_rstr(ppbus) & LPIP_SHAKE)
  600         if (--spin == 0)
  601                 return 1;
  602     return 0;
  603 }
  604 
  605 static int
  606 lpoutput (struct ifnet *ifp, struct mbuf *m,
  607           struct sockaddr *dst, struct rtentry *rt)
  608 {
  609     device_t dev = UNITODEVICE(ifp->if_dunit);
  610     device_t ppbus = device_get_parent(dev);
  611     int s, err;
  612     struct mbuf *mm;
  613     u_char *cp = "\0\0";
  614     u_char chksum = 0;
  615     int count = 0;
  616     int i, len, spin;
  617 
  618     /* We need a sensible value if we abort */
  619     cp++;
  620     ifp->if_drv_flags |= IFF_DRV_RUNNING;
  621 
  622     err = 1;                    /* assume we're aborting because of an error */
  623 
  624     s = splhigh();
  625 
  626     /* Suspend (on laptops) or receive-errors might have taken us offline */
  627     ppb_wctr(ppbus, IRQENABLE);
  628 
  629     if (ifp->if_flags & IFF_LINK0) {
  630 
  631         if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) {
  632             lprintf("&");
  633             lp_intr(dev);
  634         }
  635 
  636         /* Alert other end to pending packet */
  637         spin = LPMAXSPIN1;
  638         ppb_wdtr(ppbus, 0x08);
  639         while ((ppb_rstr(ppbus) & 0x08) == 0)
  640                 if (--spin == 0) {
  641                         goto nend;
  642                 }
  643 
  644         /* Calculate length of packet, then send that */
  645 
  646         count += 14;            /* Ethernet header len */
  647 
  648         mm = m;
  649         for (mm = m; mm; mm = mm->m_next) {
  650                 count += mm->m_len;
  651         }
  652         if (clpoutbyte(count & 0xFF, LPMAXSPIN1, ppbus))
  653                 goto nend;
  654         if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, ppbus))
  655                 goto nend;
  656 
  657         /* Send dummy ethernet header */
  658         for (i = 0; i < 12; i++) {
  659                 if (clpoutbyte(i, LPMAXSPIN1, ppbus))
  660                         goto nend;
  661                 chksum += i;
  662         }
  663 
  664         if (clpoutbyte(0x08, LPMAXSPIN1, ppbus))
  665                 goto nend;
  666         if (clpoutbyte(0x00, LPMAXSPIN1, ppbus))
  667                 goto nend;
  668         chksum += 0x08 + 0x00;          /* Add into checksum */
  669 
  670         mm = m;
  671         do {
  672                 cp = mtod(mm, u_char *);
  673                 len = mm->m_len;
  674                 while (len--) {
  675                         chksum += *cp;
  676                         if (clpoutbyte(*cp++, LPMAXSPIN2, ppbus))
  677                                 goto nend;
  678                 }
  679         } while ((mm = mm->m_next));
  680 
  681         /* Send checksum */
  682         if (clpoutbyte(chksum, LPMAXSPIN2, ppbus))
  683                 goto nend;
  684 
  685         /* Go quiescent */
  686         ppb_wdtr(ppbus, 0);
  687 
  688         err = 0;                        /* No errors */
  689 
  690         nend:
  691         if (err)  {                             /* if we didn't timeout... */
  692                 ifp->if_oerrors++;
  693                 lprintf("X");
  694         } else {
  695                 ifp->if_opackets++;
  696                 ifp->if_obytes += m->m_pkthdr.len;
  697                 if (bpf_peers_present(ifp->if_bpf))
  698                     lptap(ifp, m);
  699         }
  700 
  701         m_freem(m);
  702 
  703         if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) {
  704                 lprintf("^");
  705                 lp_intr(dev);
  706         }
  707         (void) splx(s);
  708         return 0;
  709     }
  710 
  711     if (ppb_rstr(ppbus) & LPIP_SHAKE) {
  712         lprintf("&");
  713         lp_intr(dev);
  714     }
  715 
  716     if (lpoutbyte(0x08, LPMAXSPIN1, ppbus))
  717         goto end;
  718     if (lpoutbyte(0x00, LPMAXSPIN2, ppbus))
  719         goto end;
  720 
  721     mm = m;
  722     do {
  723         cp = mtod(mm,u_char *);
  724         len = mm->m_len;
  725         while (len--)
  726             if (lpoutbyte(*cp++, LPMAXSPIN2, ppbus))
  727                 goto end;
  728     } while ((mm = mm->m_next));
  729 
  730     err = 0;                            /* no errors were encountered */
  731 
  732     end:
  733     --cp;
  734     ppb_wdtr(ppbus, txmitl[*cp] ^ 0x17);
  735 
  736     if (err)  {                         /* if we didn't timeout... */
  737         ifp->if_oerrors++;
  738         lprintf("X");
  739     } else {
  740         ifp->if_opackets++;
  741         ifp->if_obytes += m->m_pkthdr.len;
  742         if (bpf_peers_present(ifp->if_bpf))
  743             lptap(ifp, m);
  744     }
  745 
  746     m_freem(m);
  747 
  748     if (ppb_rstr(ppbus) & LPIP_SHAKE) {
  749         lprintf("^");
  750         lp_intr(dev);
  751     }
  752 
  753     (void) splx(s);
  754     return 0;
  755 }
  756 
  757 static device_method_t lp_methods[] = {
  758         /* device interface */
  759         DEVMETHOD(device_identify,      lp_identify),
  760         DEVMETHOD(device_probe,         lp_probe),
  761         DEVMETHOD(device_attach,        lp_attach),
  762 
  763         { 0, 0 }
  764 };
  765 
  766 static driver_t lp_driver = {
  767   "plip",
  768   lp_methods,
  769   sizeof(struct lp_data),
  770 };
  771 
  772 DRIVER_MODULE(plip, ppbus, lp_driver, lp_devclass, 0, 0);
  773 MODULE_DEPEND(plip, ppbus, 1, 1, 1);

Cache object: 424637220cdd94c6a2c7da2d44b0d747


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