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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 1997 Poul-Henning Kamp
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  *
   28  *      From Id: lpt.c,v 1.55.2.1 1996/11/12 09:08:38 phk Exp
   29  */
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD$");
   33 
   34 /*
   35  * Parallel port TCP/IP interfaces added.  I looked at the driver from
   36  * MACH but this is a complete rewrite, and btw. incompatible, and it
   37  * should perform better too.  I have never run the MACH driver though.
   38  *
   39  * This driver sends two bytes (0x08, 0x00) in front of each packet,
   40  * to allow us to distinguish another format later.
   41  *
   42  * Now added a Linux/Crynwr compatibility mode which is enabled using
   43  * IF_LINK0 - Tim Wilkinson.
   44  *
   45  * TODO:
   46  *    Make HDLC/PPP mode, use IF_LLC1 to enable.
   47  *
   48  * Connect the two computers using a Laplink parallel cable to use this
   49  * feature:
   50  *
   51  *      +----------------------------------------+
   52  *      |A-name A-End   B-End   Descr.  Port/Bit |
   53  *      +----------------------------------------+
   54  *      |DATA0  2       15      Data    0/0x01   |
   55  *      |-ERROR 15      2               1/0x08   |
   56  *      +----------------------------------------+
   57  *      |DATA1  3       13      Data    0/0x02   |
   58  *      |+SLCT  13      3               1/0x10   |
   59  *      +----------------------------------------+
   60  *      |DATA2  4       12      Data    0/0x04   |
   61  *      |+PE    12      4               1/0x20   |
   62  *      +----------------------------------------+
   63  *      |DATA3  5       10      Strobe  0/0x08   |
   64  *      |-ACK   10      5               1/0x40   |
   65  *      +----------------------------------------+
   66  *      |DATA4  6       11      Data    0/0x10   |
   67  *      |BUSY   11      6               1/~0x80  |
   68  *      +----------------------------------------+
   69  *      |GND    18-25   18-25   GND     -        |
   70  *      +----------------------------------------+
   71  *
   72  * Expect transfer-rates up to 75 kbyte/sec.
   73  *
   74  * If GCC could correctly grok
   75  *      register int port asm("edx")
   76  * the code would be cleaner
   77  *
   78  * Poul-Henning Kamp <phk@freebsd.org>
   79  */
   80 
   81 /*
   82  * Update for ppbus, PLIP support only - Nicolas Souchu
   83  */
   84 
   85 #include "opt_plip.h"
   86 
   87 #include <sys/param.h>
   88 #include <sys/systm.h>
   89 #include <sys/module.h>
   90 #include <sys/bus.h>
   91 #include <sys/mbuf.h>
   92 #include <sys/socket.h>
   93 #include <sys/sockio.h>
   94 #include <sys/kernel.h>
   95 #include <sys/malloc.h>
   96 
   97 #include <machine/bus.h>
   98 #include <machine/resource.h>
   99 #include <sys/rman.h>
  100 
  101 #include <net/if.h>
  102 #include <net/if_var.h>
  103 #include <net/if_types.h>
  104 #include <net/netisr.h>
  105 #include <net/route.h>
  106 
  107 #include <netinet/in.h>
  108 #include <netinet/in_var.h>
  109 
  110 #include <net/bpf.h>
  111 
  112 #include <dev/ppbus/ppbconf.h>
  113 #include "ppbus_if.h"
  114 #include <dev/ppbus/ppbio.h>
  115 
  116 #ifndef LPMTU                   /* MTU for the lp# interfaces */
  117 #define LPMTU           1500
  118 #endif
  119 
  120 #ifndef LPMAXSPIN1              /* DELAY factor for the lp# interfaces */
  121 #define LPMAXSPIN1      8000   /* Spinning for remote intr to happen */
  122 #endif
  123 
  124 #ifndef LPMAXSPIN2              /* DELAY factor for the lp# interfaces */
  125 #define LPMAXSPIN2      500     /* Spinning for remote handshake to happen */
  126 #endif
  127 
  128 #ifndef LPMAXERRS               /* Max errors before !RUNNING */
  129 #define LPMAXERRS       100
  130 #endif
  131 
  132 #define CLPIPHDRLEN     14      /* We send dummy ethernet addresses (two) + packet type in front of packet */
  133 #define CLPIP_SHAKE     0x80    /* This bit toggles between nibble reception */
  134 #define MLPIPHDRLEN     CLPIPHDRLEN
  135 
  136 #define LPIPHDRLEN      2       /* We send 0x08, 0x00 in front of packet */
  137 #define LPIP_SHAKE      0x40    /* This bit toggles between nibble reception */
  138 #if !defined(MLPIPHDRLEN) || LPIPHDRLEN > MLPIPHDRLEN
  139 #define MLPIPHDRLEN     LPIPHDRLEN
  140 #endif
  141 
  142 #define LPIPTBLSIZE     256     /* Size of octet translation table */
  143 
  144 #define lprintf         if (lptflag) printf
  145 
  146 #ifdef PLIP_DEBUG
  147 static int volatile lptflag = 1;
  148 #else
  149 static int volatile lptflag = 0;
  150 #endif
  151 
  152 struct lp_data {
  153         struct  ifnet   *sc_ifp;
  154         device_t        sc_dev;
  155         u_char          *sc_ifbuf;
  156         int             sc_iferrs;
  157 
  158         struct resource *res_irq;
  159         void            *sc_intr_cookie;
  160 };
  161 
  162 static struct mtx lp_tables_lock;
  163 MTX_SYSINIT(lp_tables, &lp_tables_lock, "plip tables", MTX_DEF);
  164 
  165 /* Tables for the lp# interface */
  166 static u_char *txmith;
  167 #define txmitl (txmith + (1 * LPIPTBLSIZE))
  168 #define trecvh (txmith + (2 * LPIPTBLSIZE))
  169 #define trecvl (txmith + (3 * LPIPTBLSIZE))
  170 
  171 static u_char *ctxmith;
  172 #define ctxmitl (ctxmith + (1 * LPIPTBLSIZE))
  173 #define ctrecvh (ctxmith + (2 * LPIPTBLSIZE))
  174 #define ctrecvl (ctxmith + (3 * LPIPTBLSIZE))
  175 
  176 /* Functions for the lp# interface */
  177 static int lpinittables(void);
  178 static int lpioctl(struct ifnet *, u_long, caddr_t);
  179 static int lpoutput(struct ifnet *, struct mbuf *, const struct sockaddr *,
  180        struct route *);
  181 static void lpstop(struct lp_data *);
  182 static void lp_intr(void *);
  183 static int lp_module_handler(module_t, int, void *);
  184 
  185 #define DEVTOSOFTC(dev) \
  186         ((struct lp_data *)device_get_softc(dev))
  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 == NULL) {
  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 == NULL) {
  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                 /* Ack. the request */
  541                 ppb_wdtr(ppbus, 0x01);
  542 
  543                 /* Get the packet length */
  544                 j = clpinbyte(LPMAXSPIN2, ppbus);
  545                 if (j == -1)
  546                         goto err;
  547                 len = j;
  548                 j = clpinbyte(LPMAXSPIN2, ppbus);
  549                 if (j == -1)
  550                         goto err;
  551                 len = len + (j << 8);
  552                 if (len > sc->sc_ifp->if_mtu + MLPIPHDRLEN)
  553                         goto err;
  554 
  555                 bp = sc->sc_ifbuf;
  556 
  557                 while (len--) {
  558                         j = clpinbyte(LPMAXSPIN2, ppbus);
  559                         if (j == -1) {
  560                                 goto err;
  561                         }
  562                         *bp++ = j;
  563                 }
  564 
  565                 /* Get and ignore checksum */
  566                 j = clpinbyte(LPMAXSPIN2, ppbus);
  567                 if (j == -1) {
  568                         goto err;
  569                 }
  570 
  571                 len = bp - sc->sc_ifbuf;
  572                 if (len <= CLPIPHDRLEN)
  573                         goto err;
  574 
  575                 sc->sc_iferrs = 0;
  576 
  577                 len -= CLPIPHDRLEN;
  578                 if_inc_counter(sc->sc_ifp, IFCOUNTER_IPACKETS, 1);
  579                 if_inc_counter(sc->sc_ifp, IFCOUNTER_IBYTES, len);
  580                 top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, sc->sc_ifp,
  581                     0);
  582                 if (top) {
  583                         ppb_unlock(ppbus);
  584                         if (bpf_peers_present(sc->sc_ifp->if_bpf))
  585                                 lptap(sc->sc_ifp, top);
  586 
  587                         M_SETFIB(top, sc->sc_ifp->if_fib);
  588 
  589                         /* mbuf is free'd on failure. */
  590                         netisr_queue(NETISR_IP, top);
  591                         ppb_lock(ppbus);
  592                 }
  593                 return;
  594         }
  595         while ((ppb_rstr(ppbus) & LPIP_SHAKE)) {
  596                 len = sc->sc_ifp->if_mtu + LPIPHDRLEN;
  597                 bp  = sc->sc_ifbuf;
  598                 while (len--) {
  599                         cl = ppb_rstr(ppbus);
  600                         ppb_wdtr(ppbus, 8);
  601 
  602                         j = LPMAXSPIN2;
  603                         while ((ppb_rstr(ppbus) & LPIP_SHAKE))
  604                                 if (!--j)
  605                                         goto err;
  606 
  607                         c = ppb_rstr(ppbus);
  608                         ppb_wdtr(ppbus, 0);
  609 
  610                         *bp++= trecvh[cl] | trecvl[c];
  611 
  612                         j = LPMAXSPIN2;
  613                         while (!((cl = ppb_rstr(ppbus)) & LPIP_SHAKE)) {
  614                                 if (cl != c &&
  615                                     (((cl = ppb_rstr(ppbus)) ^ 0xb8) & 0xf8) ==
  616                                     (c & 0xf8))
  617                                         goto end;
  618                                 if (!--j)
  619                                         goto err;
  620                         }
  621                 }
  622 
  623         end:
  624                 len = bp - sc->sc_ifbuf;
  625                 if (len <= LPIPHDRLEN)
  626                         goto err;
  627 
  628                 sc->sc_iferrs = 0;
  629 
  630                 len -= LPIPHDRLEN;
  631                 if_inc_counter(sc->sc_ifp, IFCOUNTER_IPACKETS, 1);
  632                 if_inc_counter(sc->sc_ifp, IFCOUNTER_IBYTES, len);
  633                 top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, sc->sc_ifp,
  634                     0);
  635                 if (top) {
  636                         ppb_unlock(ppbus);
  637                         if (bpf_peers_present(sc->sc_ifp->if_bpf))
  638                                 lptap(sc->sc_ifp, top);
  639 
  640                         M_SETFIB(top, sc->sc_ifp->if_fib);
  641 
  642                         /* mbuf is free'd on failure. */
  643                         netisr_queue(NETISR_IP, top);
  644                         ppb_lock(ppbus);
  645                 }
  646         }
  647         return;
  648 
  649 err:
  650         ppb_wdtr(ppbus, 0);
  651         lprintf("R");
  652         if_inc_counter(sc->sc_ifp, IFCOUNTER_IERRORS, 1);
  653         sc->sc_iferrs++;
  654 
  655         /*
  656          * We are not able to send receive anything for now,
  657          * so stop wasting our time
  658          */
  659         if (sc->sc_iferrs > LPMAXERRS) {
  660                 if_printf(sc->sc_ifp, "Too many errors, Going off-line.\n");
  661                 ppb_wctr(ppbus, 0x00);
  662                 sc->sc_ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
  663                 sc->sc_iferrs = 0;
  664         }
  665 }
  666 
  667 static __inline int
  668 lpoutbyte(u_char byte, int spin, device_t ppbus)
  669 {
  670 
  671         ppb_wdtr(ppbus, txmith[byte]);
  672         while (!(ppb_rstr(ppbus) & LPIP_SHAKE))
  673                 if (--spin == 0)
  674                         return (1);
  675         ppb_wdtr(ppbus, txmitl[byte]);
  676         while (ppb_rstr(ppbus) & LPIP_SHAKE)
  677                 if (--spin == 0)
  678                         return (1);
  679         return (0);
  680 }
  681 
  682 static int
  683 lpoutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
  684     struct route *ro)
  685 {
  686         struct lp_data *sc = ifp->if_softc;
  687         device_t dev = sc->sc_dev;
  688         device_t ppbus = device_get_parent(dev);
  689         int err;
  690         struct mbuf *mm;
  691         u_char *cp = "\0\0";
  692         u_char chksum = 0;
  693         int count = 0;
  694         int i, len, spin;
  695 
  696         /* We need a sensible value if we abort */
  697         cp++;
  698         ppb_lock(ppbus);
  699         ifp->if_drv_flags |= IFF_DRV_OACTIVE;
  700 
  701         err = 1;                /* assume we're aborting because of an error */
  702 
  703         /* Suspend (on laptops) or receive-errors might have taken us offline */
  704         ppb_wctr(ppbus, IRQENABLE);
  705 
  706         if (ifp->if_flags & IFF_LINK0) {
  707                 if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) {
  708                         lprintf("&");
  709                         lp_intr(sc);
  710                 }
  711 
  712                 /* Alert other end to pending packet */
  713                 spin = LPMAXSPIN1;
  714                 ppb_wdtr(ppbus, 0x08);
  715                 while ((ppb_rstr(ppbus) & 0x08) == 0)
  716                         if (--spin == 0) {
  717                                 goto nend;
  718                         }
  719 
  720                 /* Calculate length of packet, then send that */
  721 
  722                 count += 14;            /* Ethernet header len */
  723 
  724                 mm = m;
  725                 for (mm = m; mm; mm = mm->m_next) {
  726                         count += mm->m_len;
  727                 }
  728                 if (clpoutbyte(count & 0xFF, LPMAXSPIN1, ppbus))
  729                         goto nend;
  730                 if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, ppbus))
  731                         goto nend;
  732 
  733                 /* Send dummy ethernet header */
  734                 for (i = 0; i < 12; i++) {
  735                         if (clpoutbyte(i, LPMAXSPIN1, ppbus))
  736                                 goto nend;
  737                         chksum += i;
  738                 }
  739 
  740                 if (clpoutbyte(0x08, LPMAXSPIN1, ppbus))
  741                         goto nend;
  742                 if (clpoutbyte(0x00, LPMAXSPIN1, ppbus))
  743                         goto nend;
  744                 chksum += 0x08 + 0x00;          /* Add into checksum */
  745 
  746                 mm = m;
  747                 do {
  748                         cp = mtod(mm, u_char *);
  749                         len = mm->m_len;
  750                         while (len--) {
  751                                 chksum += *cp;
  752                                 if (clpoutbyte(*cp++, LPMAXSPIN2, ppbus))
  753                                         goto nend;
  754                         }
  755                 } while ((mm = mm->m_next));
  756 
  757                 /* Send checksum */
  758                 if (clpoutbyte(chksum, LPMAXSPIN2, ppbus))
  759                         goto nend;
  760 
  761                 /* Go quiescent */
  762                 ppb_wdtr(ppbus, 0);
  763 
  764                 err = 0;                        /* No errors */
  765 
  766         nend:
  767                 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
  768                 if (err)  {                     /* if we didn't timeout... */
  769                         if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
  770                         lprintf("X");
  771                 } else {
  772                         if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
  773                         if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len);
  774                         if (bpf_peers_present(ifp->if_bpf))
  775                                 lptap(ifp, m);
  776                 }
  777 
  778                 m_freem(m);
  779 
  780                 if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) {
  781                         lprintf("^");
  782                         lp_intr(sc);
  783                 }
  784                 ppb_unlock(ppbus);
  785                 return (0);
  786         }
  787 
  788         if (ppb_rstr(ppbus) & LPIP_SHAKE) {
  789                 lprintf("&");
  790                 lp_intr(sc);
  791         }
  792 
  793         if (lpoutbyte(0x08, LPMAXSPIN1, ppbus))
  794                 goto end;
  795         if (lpoutbyte(0x00, LPMAXSPIN2, ppbus))
  796                 goto end;
  797 
  798         mm = m;
  799         do {
  800                 cp = mtod(mm, u_char *);
  801                 len = mm->m_len;
  802                 while (len--)
  803                         if (lpoutbyte(*cp++, LPMAXSPIN2, ppbus))
  804                                 goto end;
  805         } while ((mm = mm->m_next));
  806 
  807         err = 0;                        /* no errors were encountered */
  808 
  809 end:
  810         --cp;
  811         ppb_wdtr(ppbus, txmitl[*cp] ^ 0x17);
  812 
  813         ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
  814         if (err)  {                     /* if we didn't timeout... */
  815                 if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
  816                 lprintf("X");
  817         } else {
  818                 if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
  819                 if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len);
  820                 if (bpf_peers_present(ifp->if_bpf))
  821                         lptap(ifp, m);
  822         }
  823 
  824         m_freem(m);
  825 
  826         if (ppb_rstr(ppbus) & LPIP_SHAKE) {
  827                 lprintf("^");
  828                 lp_intr(sc);
  829         }
  830 
  831         ppb_unlock(ppbus);
  832         return (0);
  833 }
  834 
  835 static device_method_t lp_methods[] = {
  836         /* device interface */
  837         DEVMETHOD(device_identify,      lp_identify),
  838         DEVMETHOD(device_probe,         lp_probe),
  839         DEVMETHOD(device_attach,        lp_attach),
  840         DEVMETHOD(device_detach,        lp_detach),
  841         { 0, 0 }
  842 };
  843 
  844 static driver_t lp_driver = {
  845         "plip",
  846         lp_methods,
  847         sizeof(struct lp_data),
  848 };
  849 
  850 DRIVER_MODULE(plip, ppbus, lp_driver, lp_module_handler, NULL);
  851 MODULE_DEPEND(plip, ppbus, 1, 1, 1);

Cache object: 7db7563cfd7330a060e81ff114474810


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