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/11.0/sys/dev/ppbus/if_plip.c 271849 2014-09-19 03:51:26Z glebius $");
   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_var.h>
  101 #include <net/if_types.h>
  102 #include <net/netisr.h>
  103 #include <net/route.h>
  104 
  105 #include <netinet/in.h>
  106 #include <netinet/in_var.h>
  107 
  108 #include <net/bpf.h>
  109 
  110 #include <dev/ppbus/ppbconf.h>
  111 #include "ppbus_if.h"
  112 #include <dev/ppbus/ppbio.h>
  113 
  114 #ifndef LPMTU                   /* MTU for the lp# interfaces */
  115 #define LPMTU           1500
  116 #endif
  117 
  118 #ifndef LPMAXSPIN1              /* DELAY factor for the lp# interfaces */
  119 #define LPMAXSPIN1      8000   /* Spinning for remote intr to happen */
  120 #endif
  121 
  122 #ifndef LPMAXSPIN2              /* DELAY factor for the lp# interfaces */
  123 #define LPMAXSPIN2      500     /* Spinning for remote handshake to happen */
  124 #endif
  125 
  126 #ifndef LPMAXERRS               /* Max errors before !RUNNING */
  127 #define LPMAXERRS       100
  128 #endif
  129 
  130 #define CLPIPHDRLEN     14      /* We send dummy ethernet addresses (two) + packet type in front of packet */
  131 #define CLPIP_SHAKE     0x80    /* This bit toggles between nibble reception */
  132 #define MLPIPHDRLEN     CLPIPHDRLEN
  133 
  134 #define LPIPHDRLEN      2       /* We send 0x08, 0x00 in front of packet */
  135 #define LPIP_SHAKE      0x40    /* This bit toggles between nibble reception */
  136 #if !defined(MLPIPHDRLEN) || LPIPHDRLEN > MLPIPHDRLEN
  137 #define MLPIPHDRLEN     LPIPHDRLEN
  138 #endif
  139 
  140 #define LPIPTBLSIZE     256     /* Size of octet translation table */
  141 
  142 #define lprintf         if (lptflag) printf
  143 
  144 #ifdef PLIP_DEBUG
  145 static int volatile lptflag = 1;
  146 #else
  147 static int volatile lptflag = 0;
  148 #endif
  149 
  150 struct lp_data {
  151         struct  ifnet   *sc_ifp;
  152         device_t        sc_dev;
  153         u_char          *sc_ifbuf;
  154         int             sc_iferrs;
  155 
  156         struct resource *res_irq;
  157         void            *sc_intr_cookie;
  158 };
  159 
  160 static struct mtx lp_tables_lock;
  161 MTX_SYSINIT(lp_tables, &lp_tables_lock, "plip tables", MTX_DEF);
  162 
  163 /* Tables for the lp# interface */
  164 static u_char *txmith;
  165 #define txmitl (txmith + (1 * LPIPTBLSIZE))
  166 #define trecvh (txmith + (2 * LPIPTBLSIZE))
  167 #define trecvl (txmith + (3 * LPIPTBLSIZE))
  168 
  169 static u_char *ctxmith;
  170 #define ctxmitl (ctxmith + (1 * LPIPTBLSIZE))
  171 #define ctrecvh (ctxmith + (2 * LPIPTBLSIZE))
  172 #define ctrecvl (ctxmith + (3 * LPIPTBLSIZE))
  173 
  174 /* Functions for the lp# interface */
  175 static int lpinittables(void);
  176 static int lpioctl(struct ifnet *, u_long, caddr_t);
  177 static int lpoutput(struct ifnet *, struct mbuf *, const struct sockaddr *,
  178        struct route *);
  179 static void lpstop(struct lp_data *);
  180 static void lp_intr(void *);
  181 static int lp_module_handler(module_t, int, void *);
  182 
  183 #define DEVTOSOFTC(dev) \
  184         ((struct lp_data *)device_get_softc(dev))
  185 
  186 static devclass_t lp_devclass;
  187 
  188 static int
  189 lp_module_handler(module_t mod, int what, void *arg)
  190 {
  191 
  192         switch (what) {
  193         case MOD_UNLOAD:
  194                 mtx_lock(&lp_tables_lock);
  195                 if (txmith != NULL) {
  196                         free(txmith, M_DEVBUF);
  197                         txmith = NULL;
  198                 }
  199                 if (ctxmith != NULL) {
  200                         free(ctxmith, M_DEVBUF);
  201                         ctxmith = NULL;
  202                 }
  203                 mtx_unlock(&lp_tables_lock);
  204                 break;
  205         case MOD_LOAD:
  206         case MOD_QUIESCE:
  207                 break;
  208         default:
  209                 return (EOPNOTSUPP);
  210         }
  211         return (0);
  212 }
  213 
  214 static void
  215 lp_identify(driver_t *driver, device_t parent)
  216 {
  217         device_t dev;
  218 
  219         dev = device_find_child(parent, "plip", -1);
  220         if (!dev)
  221                 BUS_ADD_CHILD(parent, 0, "plip", -1);
  222 }
  223 
  224 static int
  225 lp_probe(device_t dev)
  226 {
  227 
  228         device_set_desc(dev, "PLIP network interface");
  229 
  230         return (0);
  231 }
  232 
  233 static int
  234 lp_attach(device_t dev)
  235 {
  236         struct lp_data *lp = DEVTOSOFTC(dev);
  237         struct ifnet *ifp;
  238         int error, rid = 0;
  239 
  240         lp->sc_dev = dev;
  241 
  242         /*
  243          * Reserve the interrupt resource.  If we don't have one, the
  244          * attach fails.
  245          */
  246         lp->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
  247             RF_SHAREABLE);
  248         if (lp->res_irq == 0) {
  249                 device_printf(dev, "cannot reserve interrupt, failed.\n");
  250                 return (ENXIO);
  251         }
  252 
  253         ifp = lp->sc_ifp = if_alloc(IFT_PARA);
  254         if (ifp == NULL) {
  255                 return (ENOSPC);
  256         }
  257 
  258         ifp->if_softc = lp;
  259         if_initname(ifp, device_get_name(dev), device_get_unit(dev));
  260         ifp->if_mtu = LPMTU;
  261         ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST;
  262         ifp->if_ioctl = lpioctl;
  263         ifp->if_output = lpoutput;
  264         ifp->if_hdrlen = 0;
  265         ifp->if_addrlen = 0;
  266         ifp->if_snd.ifq_maxlen = ifqmaxlen;
  267         if_attach(ifp);
  268 
  269         bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
  270 
  271         /*
  272          * Attach our interrupt handler.  It is only called while we
  273          * own the ppbus.
  274          */
  275         error = bus_setup_intr(dev, lp->res_irq, INTR_TYPE_NET | INTR_MPSAFE,
  276             NULL, lp_intr, lp, &lp->sc_intr_cookie);
  277         if (error) {
  278                 bpfdetach(ifp);
  279                 if_detach(ifp);
  280                 bus_release_resource(dev, SYS_RES_IRQ, 0, lp->res_irq);
  281                 device_printf(dev, "Unable to register interrupt handler\n");
  282                 return (error);
  283         }
  284 
  285         return (0);
  286 }
  287 
  288 static int
  289 lp_detach(device_t dev)
  290 {
  291         struct lp_data *sc = device_get_softc(dev);
  292         device_t ppbus = device_get_parent(dev);
  293 
  294         ppb_lock(ppbus);
  295         lpstop(sc);
  296         ppb_unlock(ppbus);
  297         bpfdetach(sc->sc_ifp);
  298         if_detach(sc->sc_ifp);
  299         bus_teardown_intr(dev, sc->res_irq, sc->sc_intr_cookie);
  300         bus_release_resource(dev, SYS_RES_IRQ, 0, sc->res_irq);
  301         return (0);
  302 }
  303 
  304 /*
  305  * Build the translation tables for the LPIP (BSD unix) protocol.
  306  * We don't want to calculate these nasties in our tight loop, so we
  307  * precalculate them when we initialize.
  308  */
  309 static int
  310 lpinittables(void)
  311 {
  312         int i;
  313 
  314         mtx_lock(&lp_tables_lock);
  315         if (txmith == NULL)
  316                 txmith = malloc(4 * LPIPTBLSIZE, M_DEVBUF, M_NOWAIT);
  317 
  318         if (txmith == NULL) {
  319                 mtx_unlock(&lp_tables_lock);
  320                 return (1);
  321         }
  322 
  323         if (ctxmith == NULL)
  324                 ctxmith = malloc(4 * LPIPTBLSIZE, M_DEVBUF, M_NOWAIT);
  325 
  326         if (ctxmith == NULL) {
  327                 mtx_unlock(&lp_tables_lock);
  328                 return (1);
  329         }
  330 
  331         for (i = 0; i < LPIPTBLSIZE; i++) {
  332                 ctxmith[i] = (i & 0xF0) >> 4;
  333                 ctxmitl[i] = 0x10 | (i & 0x0F);
  334                 ctrecvh[i] = (i & 0x78) << 1;
  335                 ctrecvl[i] = (i & 0x78) >> 3;
  336         }
  337 
  338         for (i = 0; i < LPIPTBLSIZE; i++) {
  339                 txmith[i] = ((i & 0x80) >> 3) | ((i & 0x70) >> 4) | 0x08;
  340                 txmitl[i] = ((i & 0x08) << 1) | (i & 0x07);
  341                 trecvh[i] = ((~i) & 0x80) | ((i & 0x38) << 1);
  342                 trecvl[i] = (((~i) & 0x80) >> 4) | ((i & 0x38) >> 3);
  343         }
  344         mtx_unlock(&lp_tables_lock);
  345 
  346         return (0);
  347 }
  348 
  349 static void
  350 lpstop(struct lp_data *sc)
  351 {
  352         device_t ppbus = device_get_parent(sc->sc_dev);
  353 
  354         ppb_assert_locked(ppbus);
  355         ppb_wctr(ppbus, 0x00);
  356         sc->sc_ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
  357         free(sc->sc_ifbuf, M_DEVBUF);
  358         sc->sc_ifbuf = NULL;
  359 
  360         /* IFF_UP is not set, try to release the bus anyway */
  361         ppb_release_bus(ppbus, sc->sc_dev);
  362 }
  363 
  364 static int
  365 lpinit_locked(struct ifnet *ifp)
  366 {
  367         struct lp_data *sc = ifp->if_softc;
  368         device_t dev = sc->sc_dev;
  369         device_t ppbus = device_get_parent(dev);
  370         int error;
  371 
  372         ppb_assert_locked(ppbus);
  373         error = ppb_request_bus(ppbus, dev, PPB_DONTWAIT);
  374         if (error)
  375                 return (error);
  376 
  377         /* Now IFF_UP means that we own the bus */
  378         ppb_set_mode(ppbus, PPB_COMPATIBLE);
  379 
  380         if (lpinittables()) {
  381                 ppb_release_bus(ppbus, dev);
  382                 return (ENOBUFS);
  383         }
  384 
  385         sc->sc_ifbuf = malloc(sc->sc_ifp->if_mtu + MLPIPHDRLEN,
  386             M_DEVBUF, M_NOWAIT);
  387         if (sc->sc_ifbuf == NULL) {
  388                 ppb_release_bus(ppbus, dev);
  389                 return (ENOBUFS);
  390         }
  391 
  392         ppb_wctr(ppbus, IRQENABLE);
  393 
  394         ifp->if_drv_flags |= IFF_DRV_RUNNING;
  395         ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
  396         return (0);
  397 }
  398 
  399 /*
  400  * Process an ioctl request.
  401  */
  402 static int
  403 lpioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  404 {
  405         struct lp_data *sc = ifp->if_softc;
  406         device_t dev = sc->sc_dev;
  407         device_t ppbus = device_get_parent(dev);
  408         struct ifaddr *ifa = (struct ifaddr *)data;
  409         struct ifreq *ifr = (struct ifreq *)data;
  410         u_char *ptr;
  411         int error;
  412 
  413         switch (cmd) {
  414         case SIOCAIFADDR:
  415         case SIOCSIFADDR:
  416                 if (ifa->ifa_addr->sa_family != AF_INET)
  417                         return (EAFNOSUPPORT);
  418 
  419                 ifp->if_flags |= IFF_UP;
  420                 /* FALLTHROUGH */
  421         case SIOCSIFFLAGS:
  422                 error = 0;
  423                 ppb_lock(ppbus);
  424                 if ((!(ifp->if_flags & IFF_UP)) &&
  425                     (ifp->if_drv_flags & IFF_DRV_RUNNING))
  426                         lpstop(sc);
  427                 else if (((ifp->if_flags & IFF_UP)) &&
  428                     (!(ifp->if_drv_flags & IFF_DRV_RUNNING)))
  429                         error = lpinit_locked(ifp);
  430                 ppb_unlock(ppbus);
  431                 return (error);
  432 
  433         case SIOCSIFMTU:
  434                 ppb_lock(ppbus);
  435                 if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
  436                         ptr = malloc(ifr->ifr_mtu + MLPIPHDRLEN, M_DEVBUF,
  437                             M_NOWAIT);
  438                         if (ptr == NULL) {
  439                                 ppb_unlock(ppbus);
  440                                 return (ENOBUFS);
  441                         }
  442                         if (sc->sc_ifbuf)
  443                                 free(sc->sc_ifbuf, M_DEVBUF);
  444                         sc->sc_ifbuf = ptr;
  445                 }
  446                 sc->sc_ifp->if_mtu = ifr->ifr_mtu;
  447                 ppb_unlock(ppbus);
  448                 break;
  449 
  450         case SIOCGIFMTU:
  451                 ifr->ifr_mtu = sc->sc_ifp->if_mtu;
  452                 break;
  453 
  454         case SIOCADDMULTI:
  455         case SIOCDELMULTI:
  456                 if (ifr == 0) {
  457                         return (EAFNOSUPPORT);          /* XXX */
  458                 }
  459                 switch (ifr->ifr_addr.sa_family) {
  460                 case AF_INET:
  461                         break;
  462                 default:
  463                         return (EAFNOSUPPORT);
  464                 }
  465                 break;
  466 
  467         case SIOCGIFMEDIA:
  468                 /*
  469                  * No ifmedia support at this stage; maybe use it
  470                  * in future for eg. protocol selection.
  471                  */
  472                 return (EINVAL);
  473 
  474         default:
  475                 lprintf("LP:ioctl(0x%lx)\n", cmd);
  476                 return (EINVAL);
  477         }
  478         return (0);
  479 }
  480 
  481 static __inline int
  482 clpoutbyte(u_char byte, int spin, device_t ppbus)
  483 {
  484 
  485         ppb_wdtr(ppbus, ctxmitl[byte]);
  486         while (ppb_rstr(ppbus) & CLPIP_SHAKE)
  487                 if (--spin == 0) {
  488                         return (1);
  489                 }
  490         ppb_wdtr(ppbus, ctxmith[byte]);
  491         while (!(ppb_rstr(ppbus) & CLPIP_SHAKE))
  492                 if (--spin == 0) {
  493                         return (1);
  494                 }
  495         return (0);
  496 }
  497 
  498 static __inline int
  499 clpinbyte(int spin, device_t ppbus)
  500 {
  501         u_char c, cl;
  502 
  503         while ((ppb_rstr(ppbus) & CLPIP_SHAKE))
  504                 if (!--spin) {
  505                         return (-1);
  506                 }
  507         cl = ppb_rstr(ppbus);
  508         ppb_wdtr(ppbus, 0x10);
  509 
  510         while (!(ppb_rstr(ppbus) & CLPIP_SHAKE))
  511                 if (!--spin) {
  512                         return (-1);
  513                 }
  514         c = ppb_rstr(ppbus);
  515         ppb_wdtr(ppbus, 0x00);
  516 
  517         return (ctrecvl[cl] | ctrecvh[c]);
  518 }
  519 
  520 static void
  521 lptap(struct ifnet *ifp, struct mbuf *m)
  522 {
  523         u_int32_t af = AF_INET;
  524 
  525         bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m);
  526 }
  527 
  528 static void
  529 lp_intr(void *arg)
  530 {
  531         struct lp_data *sc = arg;
  532         device_t ppbus = device_get_parent(sc->sc_dev);
  533         int len, j;
  534         u_char *bp;
  535         u_char c, cl;
  536         struct mbuf *top;
  537 
  538         ppb_assert_locked(ppbus);
  539         if (sc->sc_ifp->if_flags & IFF_LINK0) {
  540 
  541                 /* Ack. the request */
  542                 ppb_wdtr(ppbus, 0x01);
  543 
  544                 /* Get the packet length */
  545                 j = clpinbyte(LPMAXSPIN2, ppbus);
  546                 if (j == -1)
  547                         goto err;
  548                 len = j;
  549                 j = clpinbyte(LPMAXSPIN2, ppbus);
  550                 if (j == -1)
  551                         goto err;
  552                 len = len + (j << 8);
  553                 if (len > sc->sc_ifp->if_mtu + MLPIPHDRLEN)
  554                         goto err;
  555 
  556                 bp = sc->sc_ifbuf;
  557 
  558                 while (len--) {
  559                         j = clpinbyte(LPMAXSPIN2, ppbus);
  560                         if (j == -1) {
  561                                 goto err;
  562                         }
  563                         *bp++ = j;
  564                 }
  565 
  566                 /* Get and ignore checksum */
  567                 j = clpinbyte(LPMAXSPIN2, ppbus);
  568                 if (j == -1) {
  569                         goto err;
  570                 }
  571 
  572                 len = bp - sc->sc_ifbuf;
  573                 if (len <= CLPIPHDRLEN)
  574                         goto err;
  575 
  576                 sc->sc_iferrs = 0;
  577 
  578                 len -= CLPIPHDRLEN;
  579                 if_inc_counter(sc->sc_ifp, IFCOUNTER_IPACKETS, 1);
  580                 if_inc_counter(sc->sc_ifp, IFCOUNTER_IBYTES, len);
  581                 top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, sc->sc_ifp,
  582                     0);
  583                 if (top) {
  584                         ppb_unlock(ppbus);
  585                         if (bpf_peers_present(sc->sc_ifp->if_bpf))
  586                                 lptap(sc->sc_ifp, top);
  587 
  588                         M_SETFIB(top, sc->sc_ifp->if_fib);
  589 
  590                         /* mbuf is free'd on failure. */
  591                         netisr_queue(NETISR_IP, top);
  592                         ppb_lock(ppbus);
  593                 }
  594                 return;
  595         }
  596         while ((ppb_rstr(ppbus) & LPIP_SHAKE)) {
  597                 len = sc->sc_ifp->if_mtu + LPIPHDRLEN;
  598                 bp  = sc->sc_ifbuf;
  599                 while (len--) {
  600 
  601                         cl = ppb_rstr(ppbus);
  602                         ppb_wdtr(ppbus, 8);
  603 
  604                         j = LPMAXSPIN2;
  605                         while ((ppb_rstr(ppbus) & LPIP_SHAKE))
  606                                 if (!--j)
  607                                         goto err;
  608 
  609                         c = ppb_rstr(ppbus);
  610                         ppb_wdtr(ppbus, 0);
  611 
  612                         *bp++= trecvh[cl] | trecvl[c];
  613 
  614                         j = LPMAXSPIN2;
  615                         while (!((cl = ppb_rstr(ppbus)) & LPIP_SHAKE)) {
  616                                 if (cl != c &&
  617                                     (((cl = ppb_rstr(ppbus)) ^ 0xb8) & 0xf8) ==
  618                                     (c & 0xf8))
  619                                         goto end;
  620                                 if (!--j)
  621                                         goto err;
  622                         }
  623                 }
  624 
  625         end:
  626                 len = bp - sc->sc_ifbuf;
  627                 if (len <= LPIPHDRLEN)
  628                         goto err;
  629 
  630                 sc->sc_iferrs = 0;
  631 
  632                 len -= LPIPHDRLEN;
  633                 if_inc_counter(sc->sc_ifp, IFCOUNTER_IPACKETS, 1);
  634                 if_inc_counter(sc->sc_ifp, IFCOUNTER_IBYTES, len);
  635                 top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, sc->sc_ifp,
  636                     0);
  637                 if (top) {
  638                         ppb_unlock(ppbus);
  639                         if (bpf_peers_present(sc->sc_ifp->if_bpf))
  640                                 lptap(sc->sc_ifp, top);
  641 
  642                         M_SETFIB(top, sc->sc_ifp->if_fib);
  643 
  644                         /* mbuf is free'd on failure. */
  645                         netisr_queue(NETISR_IP, top);
  646                         ppb_lock(ppbus);
  647                 }
  648         }
  649         return;
  650 
  651 err:
  652         ppb_wdtr(ppbus, 0);
  653         lprintf("R");
  654         if_inc_counter(sc->sc_ifp, IFCOUNTER_IERRORS, 1);
  655         sc->sc_iferrs++;
  656 
  657         /*
  658          * We are not able to send receive anything for now,
  659          * so stop wasting our time
  660          */
  661         if (sc->sc_iferrs > LPMAXERRS) {
  662                 if_printf(sc->sc_ifp, "Too many errors, Going off-line.\n");
  663                 ppb_wctr(ppbus, 0x00);
  664                 sc->sc_ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
  665                 sc->sc_iferrs = 0;
  666         }
  667 }
  668 
  669 static __inline int
  670 lpoutbyte(u_char byte, int spin, device_t ppbus)
  671 {
  672 
  673         ppb_wdtr(ppbus, txmith[byte]);
  674         while (!(ppb_rstr(ppbus) & LPIP_SHAKE))
  675                 if (--spin == 0)
  676                         return (1);
  677         ppb_wdtr(ppbus, txmitl[byte]);
  678         while (ppb_rstr(ppbus) & LPIP_SHAKE)
  679                 if (--spin == 0)
  680                         return (1);
  681         return (0);
  682 }
  683 
  684 static int
  685 lpoutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
  686     struct route *ro)
  687 {
  688         struct lp_data *sc = ifp->if_softc;
  689         device_t dev = sc->sc_dev;
  690         device_t ppbus = device_get_parent(dev);
  691         int err;
  692         struct mbuf *mm;
  693         u_char *cp = "\0\0";
  694         u_char chksum = 0;
  695         int count = 0;
  696         int i, len, spin;
  697 
  698         /* We need a sensible value if we abort */
  699         cp++;
  700         ppb_lock(ppbus);
  701         ifp->if_drv_flags |= IFF_DRV_OACTIVE;
  702 
  703         err = 1;                /* assume we're aborting because of an error */
  704 
  705         /* Suspend (on laptops) or receive-errors might have taken us offline */
  706         ppb_wctr(ppbus, IRQENABLE);
  707 
  708         if (ifp->if_flags & IFF_LINK0) {
  709                 if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) {
  710                         lprintf("&");
  711                         lp_intr(sc);
  712                 }
  713 
  714                 /* Alert other end to pending packet */
  715                 spin = LPMAXSPIN1;
  716                 ppb_wdtr(ppbus, 0x08);
  717                 while ((ppb_rstr(ppbus) & 0x08) == 0)
  718                         if (--spin == 0) {
  719                                 goto nend;
  720                         }
  721 
  722                 /* Calculate length of packet, then send that */
  723 
  724                 count += 14;            /* Ethernet header len */
  725 
  726                 mm = m;
  727                 for (mm = m; mm; mm = mm->m_next) {
  728                         count += mm->m_len;
  729                 }
  730                 if (clpoutbyte(count & 0xFF, LPMAXSPIN1, ppbus))
  731                         goto nend;
  732                 if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, ppbus))
  733                         goto nend;
  734 
  735                 /* Send dummy ethernet header */
  736                 for (i = 0; i < 12; i++) {
  737                         if (clpoutbyte(i, LPMAXSPIN1, ppbus))
  738                                 goto nend;
  739                         chksum += i;
  740                 }
  741 
  742                 if (clpoutbyte(0x08, LPMAXSPIN1, ppbus))
  743                         goto nend;
  744                 if (clpoutbyte(0x00, LPMAXSPIN1, ppbus))
  745                         goto nend;
  746                 chksum += 0x08 + 0x00;          /* Add into checksum */
  747 
  748                 mm = m;
  749                 do {
  750                         cp = mtod(mm, u_char *);
  751                         len = mm->m_len;
  752                         while (len--) {
  753                                 chksum += *cp;
  754                                 if (clpoutbyte(*cp++, LPMAXSPIN2, ppbus))
  755                                         goto nend;
  756                         }
  757                 } while ((mm = mm->m_next));
  758 
  759                 /* Send checksum */
  760                 if (clpoutbyte(chksum, LPMAXSPIN2, ppbus))
  761                         goto nend;
  762 
  763                 /* Go quiescent */
  764                 ppb_wdtr(ppbus, 0);
  765 
  766                 err = 0;                        /* No errors */
  767 
  768         nend:
  769                 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
  770                 if (err)  {                     /* if we didn't timeout... */
  771                         if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
  772                         lprintf("X");
  773                 } else {
  774                         if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
  775                         if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len);
  776                         if (bpf_peers_present(ifp->if_bpf))
  777                                 lptap(ifp, m);
  778                 }
  779 
  780                 m_freem(m);
  781 
  782                 if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) {
  783                         lprintf("^");
  784                         lp_intr(sc);
  785                 }
  786                 ppb_unlock(ppbus);
  787                 return (0);
  788         }
  789 
  790         if (ppb_rstr(ppbus) & LPIP_SHAKE) {
  791                 lprintf("&");
  792                 lp_intr(sc);
  793         }
  794 
  795         if (lpoutbyte(0x08, LPMAXSPIN1, ppbus))
  796                 goto end;
  797         if (lpoutbyte(0x00, LPMAXSPIN2, ppbus))
  798                 goto end;
  799 
  800         mm = m;
  801         do {
  802                 cp = mtod(mm, u_char *);
  803                 len = mm->m_len;
  804                 while (len--)
  805                         if (lpoutbyte(*cp++, LPMAXSPIN2, ppbus))
  806                                 goto end;
  807         } while ((mm = mm->m_next));
  808 
  809         err = 0;                        /* no errors were encountered */
  810 
  811 end:
  812         --cp;
  813         ppb_wdtr(ppbus, txmitl[*cp] ^ 0x17);
  814 
  815         ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
  816         if (err)  {                     /* if we didn't timeout... */
  817                 if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
  818                 lprintf("X");
  819         } else {
  820                 if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
  821                 if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len);
  822                 if (bpf_peers_present(ifp->if_bpf))
  823                         lptap(ifp, m);
  824         }
  825 
  826         m_freem(m);
  827 
  828         if (ppb_rstr(ppbus) & LPIP_SHAKE) {
  829                 lprintf("^");
  830                 lp_intr(sc);
  831         }
  832 
  833         ppb_unlock(ppbus);
  834         return (0);
  835 }
  836 
  837 static device_method_t lp_methods[] = {
  838         /* device interface */
  839         DEVMETHOD(device_identify,      lp_identify),
  840         DEVMETHOD(device_probe,         lp_probe),
  841         DEVMETHOD(device_attach,        lp_attach),
  842         DEVMETHOD(device_detach,        lp_detach),
  843 
  844         { 0, 0 }
  845 };
  846 
  847 static driver_t lp_driver = {
  848         "plip",
  849         lp_methods,
  850         sizeof(struct lp_data),
  851 };
  852 
  853 DRIVER_MODULE(plip, ppbus, lp_driver, lp_devclass, lp_module_handler, 0);
  854 MODULE_DEPEND(plip, ppbus, 1, 1, 1);

Cache object: 515692be1fae58d802fa5676b6038610


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