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

Cache object: 0527a60d84828d0eac8deefe782cdb8a


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