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/netif/plip/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  * $FreeBSD: src/sys/dev/ppbus/if_plip.c,v 1.19.2.1 2000/05/24 00:20:57 n_hibma Exp $
   28  */
   29 
   30 /*
   31  * Parallel port TCP/IP interfaces added.  I looked at the driver from
   32  * MACH but this is a complete rewrite, and btw. incompatible, and it
   33  * should perform better too.  I have never run the MACH driver though.
   34  *
   35  * This driver sends two bytes (0x08, 0x00) in front of each packet,
   36  * to allow us to distinguish another format later.
   37  *
   38  * Now added an Linux/Crynwr compatibility mode which is enabled using
   39  * IF_LINK0 - Tim Wilkinson.
   40  *
   41  * TODO:
   42  *    Make HDLC/PPP mode, use IF_LLC1 to enable.
   43  *
   44  * Connect the two computers using a Laplink parallel cable to use this
   45  * feature:
   46  *
   47  *      +----------------------------------------+
   48  *      |A-name A-End   B-End   Descr.  Port/Bit |
   49  *      +----------------------------------------+
   50  *      |DATA0  2       15      Data    0/0x01   |
   51  *      |-ERROR 15      2               1/0x08   |
   52  *      +----------------------------------------+
   53  *      |DATA1  3       13      Data    0/0x02   |
   54  *      |+SLCT  13      3               1/0x10   |
   55  *      +----------------------------------------+
   56  *      |DATA2  4       12      Data    0/0x04   |
   57  *      |+PE    12      4               1/0x20   |
   58  *      +----------------------------------------+
   59  *      |DATA3  5       10      Strobe  0/0x08   |
   60  *      |-ACK   10      5               1/0x40   |
   61  *      +----------------------------------------+
   62  *      |DATA4  6       11      Data    0/0x10   |
   63  *      |BUSY   11      6               1/~0x80  |
   64  *      +----------------------------------------+
   65  *      |GND    18-25   18-25   GND     -        |
   66  *      +----------------------------------------+
   67  *
   68  * Expect transfer-rates up to 75 kbyte/sec.
   69  *
   70  * If GCC could correctly grok
   71  *      register int port asm("edx")
   72  * the code would be cleaner
   73  *
   74  * Poul-Henning Kamp <phk@freebsd.org>
   75  */
   76 
   77 /*
   78  * Update for ppbus, PLIP support only - Nicolas Souchu
   79  */ 
   80 
   81 #include "opt_plip.h"
   82 
   83 #include <sys/param.h>
   84 #include <sys/systm.h>
   85 #include <sys/module.h>
   86 #include <sys/bus.h>
   87 #include <sys/mbuf.h>
   88 #include <sys/socket.h>
   89 #include <sys/sockio.h>
   90 #include <sys/kernel.h>
   91 #include <sys/malloc.h>
   92 #include <sys/rman.h>
   93 #include <sys/thread2.h>
   94 
   95 #include <machine/clock.h>
   96 
   97 #include <net/if.h>
   98 #include <net/ifq_var.h>
   99 #include <net/if_types.h>
  100 #include <net/netisr.h>
  101 
  102 #include <netinet/in.h>
  103 #include <netinet/in_var.h>
  104 
  105 #include <net/bpf.h>
  106 
  107 #include <bus/ppbus/ppbconf.h>
  108 #include "ppbus_if.h"
  109 #include <bus/ppbus/ppbio.h>
  110 
  111 #ifndef LPMTU                   /* MTU for the lp# interfaces */
  112 #define LPMTU   1500
  113 #endif
  114 
  115 #ifndef LPMAXSPIN1              /* DELAY factor for the lp# interfaces */
  116 #define LPMAXSPIN1      8000   /* Spinning for remote intr to happen */
  117 #endif
  118 
  119 #ifndef LPMAXSPIN2              /* DELAY factor for the lp# interfaces */
  120 #define LPMAXSPIN2      500     /* Spinning for remote handshake to happen */
  121 #endif
  122 
  123 #ifndef LPMAXERRS               /* Max errors before !RUNNING */
  124 #define LPMAXERRS       100
  125 #endif
  126 
  127 #define CLPIPHDRLEN     14      /* We send dummy ethernet addresses (two) + packet type in front of packet */
  128 #define CLPIP_SHAKE     0x80    /* This bit toggles between nibble reception */
  129 #define MLPIPHDRLEN     CLPIPHDRLEN
  130 
  131 #define LPIPHDRLEN      2       /* We send 0x08, 0x00 in front of packet */
  132 #define LPIP_SHAKE      0x40    /* This bit toggles between nibble reception */
  133 #if !defined(MLPIPHDRLEN) || LPIPHDRLEN > MLPIPHDRLEN
  134 #define MLPIPHDRLEN     LPIPHDRLEN
  135 #endif
  136 
  137 #define LPIPTBLSIZE     256     /* Size of octet translation table */
  138 
  139 #define lprintf         if (lptflag) kprintf
  140 
  141 #ifdef PLIP_DEBUG
  142 static int volatile lptflag = 1;
  143 #else
  144 static int volatile lptflag = 0;
  145 #endif
  146 
  147 struct lp_data {
  148         unsigned short lp_unit;
  149 
  150         struct  ifnet   sc_if;
  151         u_char          *sc_ifbuf;
  152         int             sc_iferrs;
  153 
  154         struct resource *res_irq;
  155 };
  156 
  157 /* Tables for the lp# interface */
  158 static u_char *txmith;
  159 #define txmitl (txmith+(1*LPIPTBLSIZE))
  160 #define trecvh (txmith+(2*LPIPTBLSIZE))
  161 #define trecvl (txmith+(3*LPIPTBLSIZE))
  162 
  163 static u_char *ctxmith;
  164 #define ctxmitl (ctxmith+(1*LPIPTBLSIZE))
  165 #define ctrecvh (ctxmith+(2*LPIPTBLSIZE))
  166 #define ctrecvl (ctxmith+(3*LPIPTBLSIZE))
  167 
  168 /* Functions for the lp# interface */
  169 static int lpinittables(void);
  170 static int lpioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
  171 static int lpoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
  172         struct rtentry *);
  173 static void lp_intr(void *);
  174 
  175 #define DEVTOSOFTC(dev) \
  176         ((struct lp_data *)device_get_softc(dev))
  177 #define UNITOSOFTC(unit) \
  178         ((struct lp_data *)devclass_get_softc(lp_devclass, (unit)))
  179 #define UNITODEVICE(unit) \
  180         (devclass_get_device(lp_devclass, (unit)))
  181 
  182 static devclass_t lp_devclass;
  183 
  184 /*
  185  * lpprobe()
  186  */
  187 static int
  188 lp_probe(device_t dev)
  189 {
  190         device_t ppbus = device_get_parent(dev);
  191         struct lp_data *lp;
  192         int zero = 0;
  193         uintptr_t irq;
  194 
  195         lp = DEVTOSOFTC(dev);
  196 
  197         /* retrieve the ppbus irq */
  198         BUS_READ_IVAR(ppbus, dev, PPBUS_IVAR_IRQ, &irq);
  199 
  200         /* if we haven't interrupts, the probe fails */
  201         if (irq == -1) {
  202                 device_printf(dev, "not an interrupt driven port, failed.\n");
  203                 return (ENXIO);
  204         }
  205 
  206         /* reserve the interrupt resource, expecting irq is available to continue */
  207         lp->res_irq = bus_alloc_legacy_irq_resource(dev, &zero, irq,
  208             RF_SHAREABLE);
  209         if (lp->res_irq == NULL) {
  210                 device_printf(dev, "cannot reserve interrupt, failed.\n");
  211                 return (ENXIO);
  212         }
  213 
  214         /*
  215          * lp dependent initialisation.
  216          */
  217         lp->lp_unit = device_get_unit(dev);
  218 
  219         device_set_desc(dev, "PLIP network interface");
  220 
  221         return (0);
  222 }
  223 
  224 static int
  225 lp_attach (device_t dev)
  226 {
  227         struct lp_data *lp = DEVTOSOFTC(dev);
  228         struct ifnet *ifp = &lp->sc_if;
  229 
  230         ifp->if_softc = lp;
  231         if_initname(ifp, "lp", device_get_unit(dev));
  232         ifp->if_mtu = LPMTU;
  233         ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST;
  234         ifp->if_ioctl = lpioctl;
  235         ifp->if_output = lpoutput;
  236         ifp->if_type = IFT_PARA;
  237         ifp->if_hdrlen = 0;
  238         ifp->if_addrlen = 0;
  239         ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN);
  240         if_attach(ifp, NULL);
  241 
  242         bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
  243 
  244         return (0);
  245 }
  246 /*
  247  * Build the translation tables for the LPIP (BSD unix) protocol.
  248  * We don't want to calculate these nasties in our tight loop, so we
  249  * precalculate them when we initialize.
  250  */
  251 static int
  252 lpinittables (void)
  253 {
  254     int i;
  255 
  256     if (!txmith)
  257         txmith = kmalloc(4*LPIPTBLSIZE, M_DEVBUF, M_WAITOK);
  258 
  259     if (!ctxmith)
  260         ctxmith = kmalloc(4*LPIPTBLSIZE, M_DEVBUF, M_WAITOK);
  261 
  262     for (i=0; i < LPIPTBLSIZE; i++) {
  263         ctxmith[i] = (i & 0xF0) >> 4;
  264         ctxmitl[i] = 0x10 | (i & 0x0F);
  265         ctrecvh[i] = (i & 0x78) << 1;
  266         ctrecvl[i] = (i & 0x78) >> 3;
  267     }
  268 
  269     for (i=0; i < LPIPTBLSIZE; i++) {
  270         txmith[i] = ((i & 0x80) >> 3) | ((i & 0x70) >> 4) | 0x08;
  271         txmitl[i] = ((i & 0x08) << 1) | (i & 0x07);
  272         trecvh[i] = ((~i) & 0x80) | ((i & 0x38) << 1);
  273         trecvl[i] = (((~i) & 0x80) >> 4) | ((i & 0x38) >> 3);
  274     }
  275 
  276     return 0;
  277 }
  278 
  279 /*
  280  * Process an ioctl request.
  281  */
  282 
  283 static int
  284 lpioctl (struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
  285 {
  286     device_t dev = UNITODEVICE(ifp->if_dunit);
  287     device_t ppbus = device_get_parent(dev);
  288     struct lp_data *sc = DEVTOSOFTC(dev);
  289     struct ifaddr *ifa = (struct ifaddr *)data;
  290     struct ifreq *ifr = (struct ifreq *)data;
  291     u_char *ptr;
  292     void *ih;
  293     int error;
  294 
  295     switch (cmd) {
  296 
  297     case SIOCSIFDSTADDR:
  298     case SIOCAIFADDR:
  299     case SIOCSIFADDR:
  300         if (ifa->ifa_addr->sa_family != AF_INET)
  301             return EAFNOSUPPORT;
  302 
  303         ifp->if_flags |= IFF_UP;
  304         /* FALLTHROUGH */
  305     case SIOCSIFFLAGS:
  306         if ((!(ifp->if_flags & IFF_UP)) && (ifp->if_flags & IFF_RUNNING)) {
  307 
  308             ppb_wctr(ppbus, 0x00);
  309             ifp->if_flags &= ~IFF_RUNNING;
  310 
  311             /* IFF_UP is not set, try to release the bus anyway */
  312             ppb_release_bus(ppbus, dev);
  313             break;
  314         }
  315         if (((ifp->if_flags & IFF_UP)) && (!(ifp->if_flags & IFF_RUNNING))) {
  316 
  317             /* XXX
  318              * Should the request be interruptible?
  319              */
  320             if ((error = ppb_request_bus(ppbus, dev, PPB_WAIT|PPB_INTR)))
  321                 return (error);
  322 
  323             /* Now IFF_UP means that we own the bus */
  324 
  325             ppb_set_mode(ppbus, PPB_COMPATIBLE);
  326 
  327             if (lpinittables()) {
  328                 ppb_release_bus(ppbus, dev);
  329                 return ENOBUFS;
  330             }
  331 
  332             sc->sc_ifbuf = kmalloc(sc->sc_if.if_mtu + MLPIPHDRLEN,
  333                                   M_DEVBUF, M_WAITOK);
  334 
  335             /* attach our interrupt handler, later detached when the bus is released */
  336             error = BUS_SETUP_INTR(ppbus, dev, sc->res_irq, 0,
  337                                    lp_intr, dev, &ih, NULL, NULL);
  338             if (error) {
  339                 ppb_release_bus(ppbus, dev);
  340                 return (error);
  341             }
  342 
  343             ppb_wctr(ppbus, IRQENABLE);
  344             ifp->if_flags |= IFF_RUNNING;
  345         }
  346         break;
  347 
  348     case SIOCSIFMTU:
  349         ptr = sc->sc_ifbuf;
  350         sc->sc_ifbuf = kmalloc(ifr->ifr_mtu+MLPIPHDRLEN, M_DEVBUF, M_WAITOK);
  351         if (ptr)
  352             kfree(ptr,M_DEVBUF);
  353         sc->sc_if.if_mtu = ifr->ifr_mtu;
  354         break;
  355 
  356     case SIOCGIFMTU:
  357         ifr->ifr_mtu = sc->sc_if.if_mtu;
  358         break;
  359 
  360     case SIOCADDMULTI:
  361     case SIOCDELMULTI:
  362         if (ifr == NULL) {
  363             return EAFNOSUPPORT;                /* XXX */
  364         }
  365         switch (ifr->ifr_addr.sa_family) {
  366 
  367         case AF_INET:
  368             break;
  369 
  370         default:
  371             return EAFNOSUPPORT;
  372         }
  373         break;
  374 
  375     case SIOCGIFMEDIA:
  376         /*
  377          * No ifmedia support at this stage; maybe use it
  378          * in future for eg. protocol selection.
  379          */
  380         return EINVAL;
  381 
  382     default:
  383         lprintf("LP:ioctl(0x%lx)\n", cmd);
  384         return EINVAL;
  385     }
  386     return 0;
  387 }
  388 
  389 static __inline int
  390 clpoutbyte (u_char byte, int spin, device_t ppbus)
  391 {
  392         ppb_wdtr(ppbus, ctxmitl[byte]);
  393         while (ppb_rstr(ppbus) & CLPIP_SHAKE)
  394                 if (--spin == 0) {
  395                         return 1;
  396                 }
  397         ppb_wdtr(ppbus, ctxmith[byte]);
  398         while (!(ppb_rstr(ppbus) & CLPIP_SHAKE))
  399                 if (--spin == 0) {
  400                         return 1;
  401                 }
  402         return 0;
  403 }
  404 
  405 static __inline int
  406 clpinbyte (int spin, device_t ppbus)
  407 {
  408         u_char c, cl;
  409 
  410         while((ppb_rstr(ppbus) & CLPIP_SHAKE))
  411             if(!--spin) {
  412                 return -1;
  413             }
  414         cl = ppb_rstr(ppbus);
  415         ppb_wdtr(ppbus, 0x10);
  416 
  417         while(!(ppb_rstr(ppbus) & CLPIP_SHAKE))
  418             if(!--spin) {
  419                 return -1;
  420             }
  421         c = ppb_rstr(ppbus);
  422         ppb_wdtr(ppbus, 0x00);
  423 
  424         return (ctrecvl[cl] | ctrecvh[c]);
  425 }
  426 
  427 static void
  428 lptap(struct ifnet *ifp, struct mbuf *m)
  429 {
  430         /*
  431          * We need to prepend the address family as a four byte field.
  432          */
  433         static const uint32_t af = AF_INET;
  434 
  435         if (ifp->if_bpf) {
  436                 bpf_gettoken();
  437                 if (ifp->if_bpf)
  438                         bpf_ptap(ifp->if_bpf, m, &af, sizeof(af));
  439                 bpf_reltoken();
  440         }
  441 }
  442 
  443 static void
  444 lp_intr (void *arg)
  445 {
  446         device_t dev = (device_t)arg;
  447         device_t ppbus = device_get_parent(dev);
  448         struct lp_data *sc = DEVTOSOFTC(dev);
  449         int len, j;
  450         u_char *bp;
  451         u_char c, cl;
  452         struct mbuf *top;
  453 
  454         crit_enter();
  455 
  456         if (sc->sc_if.if_flags & IFF_LINK0) {
  457 
  458             /* Ack. the request */
  459             ppb_wdtr(ppbus, 0x01);
  460 
  461             /* Get the packet length */
  462             j = clpinbyte(LPMAXSPIN2, ppbus);
  463             if (j == -1)
  464                 goto err;
  465             len = j;
  466             j = clpinbyte(LPMAXSPIN2, ppbus);
  467             if (j == -1)
  468                 goto err;
  469             len = len + (j << 8);
  470             if (len > sc->sc_if.if_mtu + MLPIPHDRLEN)
  471                 goto err;
  472 
  473             bp  = sc->sc_ifbuf;
  474         
  475             while (len--) {
  476                 j = clpinbyte(LPMAXSPIN2, ppbus);
  477                 if (j == -1) {
  478                     goto err;
  479                 }
  480                 *bp++ = j;
  481             }
  482             /* Get and ignore checksum */
  483             j = clpinbyte(LPMAXSPIN2, ppbus);
  484             if (j == -1) {
  485                 goto err;
  486             }
  487 
  488             len = bp - sc->sc_ifbuf;
  489             if (len <= CLPIPHDRLEN)
  490                 goto err;
  491 
  492             sc->sc_iferrs = 0;
  493 
  494             len -= CLPIPHDRLEN;
  495             IFNET_STAT_INC(&sc->sc_if, ipackets, 1);
  496             IFNET_STAT_INC(&sc->sc_if, ibytes, len);
  497             top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, &sc->sc_if, 0);
  498             if (top) {
  499                 if (sc->sc_if.if_bpf)
  500                     lptap(&sc->sc_if, top);
  501                 netisr_queue(NETISR_IP, top);
  502             }
  503             goto done;
  504         }
  505         while ((ppb_rstr(ppbus) & LPIP_SHAKE)) {
  506             len = sc->sc_if.if_mtu + LPIPHDRLEN;
  507             bp  = sc->sc_ifbuf;
  508             while (len--) {
  509 
  510                 cl = ppb_rstr(ppbus);
  511                 ppb_wdtr(ppbus, 8);
  512 
  513                 j = LPMAXSPIN2;
  514                 while((ppb_rstr(ppbus) & LPIP_SHAKE))
  515                     if(!--j) goto err;
  516 
  517                 c = ppb_rstr(ppbus);
  518                 ppb_wdtr(ppbus, 0);
  519 
  520                 *bp++= trecvh[cl] | trecvl[c];
  521 
  522                 j = LPMAXSPIN2;
  523                 while (!((cl=ppb_rstr(ppbus)) & LPIP_SHAKE)) {
  524                     if (cl != c &&
  525                         (((cl = ppb_rstr(ppbus)) ^ 0xb8) & 0xf8) ==
  526                           (c & 0xf8))
  527                         goto end;
  528                     if (!--j) goto err;
  529                 }
  530             }
  531 
  532         end:
  533             len = bp - sc->sc_ifbuf;
  534             if (len <= LPIPHDRLEN)
  535                 goto err;
  536 
  537             sc->sc_iferrs = 0;
  538 
  539             len -= LPIPHDRLEN;
  540             IFNET_STAT_INC(&sc->sc_if, ipackets, 1);
  541             IFNET_STAT_INC(&sc->sc_if, ibytes, len);
  542             top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, &sc->sc_if, 0);
  543             if (top) {
  544                 if (sc->sc_if.if_bpf)
  545                     lptap(&sc->sc_if, top);
  546                 netisr_queue(NETISR_IP, top);
  547             }
  548         }
  549         goto done;
  550 
  551     err:
  552         ppb_wdtr(ppbus, 0);
  553         lprintf("R");
  554         IFNET_STAT_INC(&sc->sc_if, ierrors, 1);
  555         sc->sc_iferrs++;
  556 
  557         /*
  558          * We are not able to send receive anything for now,
  559          * so stop wasting our time
  560          */
  561         if (sc->sc_iferrs > LPMAXERRS) {
  562             kprintf("lp%d: Too many errors, Going off-line.\n", device_get_unit(dev));
  563             ppb_wctr(ppbus, 0x00);
  564             sc->sc_if.if_flags &= ~IFF_RUNNING;
  565             sc->sc_iferrs=0;
  566         }
  567 
  568     done:
  569         crit_exit();
  570         return;
  571 }
  572 
  573 static __inline int
  574 lpoutbyte (u_char byte, int spin, device_t ppbus)
  575 {
  576     ppb_wdtr(ppbus, txmith[byte]);
  577     while (!(ppb_rstr(ppbus) & LPIP_SHAKE))
  578         if (--spin == 0)
  579                 return 1;
  580     ppb_wdtr(ppbus, txmitl[byte]);
  581     while (ppb_rstr(ppbus) & LPIP_SHAKE)
  582         if (--spin == 0)
  583                 return 1;
  584     return 0;
  585 }
  586 
  587 static int
  588 lpoutput (struct ifnet *ifp, struct mbuf *m,
  589           struct sockaddr *dst, struct rtentry *rt)
  590 {
  591     device_t dev = UNITODEVICE(ifp->if_dunit);
  592     device_t ppbus = device_get_parent(dev);
  593     int err;
  594     struct mbuf *mm;
  595     u_char *cp = "\0\0";
  596     u_char chksum = 0;
  597     int count = 0;
  598     int i, len, spin;
  599 
  600     /* We need a sensible value if we abort */
  601     cp++;
  602     ifp->if_flags |= IFF_RUNNING;
  603 
  604     err = 1;                    /* assume we're aborting because of an error */
  605 
  606     crit_enter();
  607 
  608     /* Suspend (on laptops) or receive-errors might have taken us offline */
  609     ppb_wctr(ppbus, IRQENABLE);
  610 
  611     if (ifp->if_flags & IFF_LINK0) {
  612 
  613         if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) {
  614             lprintf("&");
  615             lp_intr(dev);
  616         }
  617 
  618         /* Alert other end to pending packet */
  619         spin = LPMAXSPIN1;
  620         ppb_wdtr(ppbus, 0x08);
  621         while ((ppb_rstr(ppbus) & 0x08) == 0)
  622                 if (--spin == 0) {
  623                         goto nend;
  624                 }
  625 
  626         /* Calculate length of packet, then send that */
  627 
  628         count += 14;            /* Ethernet header len */
  629 
  630         mm = m;
  631         for (mm = m; mm; mm = mm->m_next) {
  632                 count += mm->m_len;
  633         }
  634         if (clpoutbyte(count & 0xFF, LPMAXSPIN1, ppbus))
  635                 goto nend;
  636         if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, ppbus))
  637                 goto nend;
  638 
  639         /* Send dummy ethernet header */
  640         for (i = 0; i < 12; i++) {
  641                 if (clpoutbyte(i, LPMAXSPIN1, ppbus))
  642                         goto nend;
  643                 chksum += i;
  644         }
  645 
  646         if (clpoutbyte(0x08, LPMAXSPIN1, ppbus))
  647                 goto nend;
  648         if (clpoutbyte(0x00, LPMAXSPIN1, ppbus))
  649                 goto nend;
  650         chksum += 0x08 + 0x00;          /* Add into checksum */
  651 
  652         mm = m;
  653         do {
  654                 cp = mtod(mm, u_char *);
  655                 len = mm->m_len;
  656                 while (len--) {
  657                         chksum += *cp;
  658                         if (clpoutbyte(*cp++, LPMAXSPIN2, ppbus))
  659                                 goto nend;
  660                 }
  661         } while ((mm = mm->m_next));
  662 
  663         /* Send checksum */
  664         if (clpoutbyte(chksum, LPMAXSPIN2, ppbus))
  665                 goto nend;
  666 
  667         /* Go quiescent */
  668         ppb_wdtr(ppbus, 0);
  669 
  670         err = 0;                        /* No errors */
  671 
  672         nend:
  673         if (err)  {                             /* if we didn't timeout... */
  674                 IFNET_STAT_INC(ifp, oerrors, 1);
  675                 lprintf("X");
  676         } else {
  677                 IFNET_STAT_INC(ifp, opackets, 1);
  678                 IFNET_STAT_INC(ifp, obytes, m->m_pkthdr.len);
  679                 if (ifp->if_bpf)
  680                     lptap(ifp, m);
  681         }
  682 
  683         m_freem(m);
  684 
  685         if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) {
  686                 lprintf("^");
  687                 lp_intr(dev);
  688         }
  689         crit_exit();
  690         return 0;
  691     }
  692 
  693     if (ppb_rstr(ppbus) & LPIP_SHAKE) {
  694         lprintf("&");
  695         lp_intr(dev);
  696     }
  697 
  698     if (lpoutbyte(0x08, LPMAXSPIN1, ppbus))
  699         goto end;
  700     if (lpoutbyte(0x00, LPMAXSPIN2, ppbus))
  701         goto end;
  702 
  703     mm = m;
  704     do {
  705         cp = mtod(mm,u_char *);
  706         len = mm->m_len;
  707         while (len--)
  708             if (lpoutbyte(*cp++, LPMAXSPIN2, ppbus))
  709                 goto end;
  710     } while ((mm = mm->m_next));
  711 
  712     err = 0;                            /* no errors were encountered */
  713 
  714     end:
  715     --cp;
  716     ppb_wdtr(ppbus, txmitl[*cp] ^ 0x17);
  717 
  718     if (err)  {                         /* if we didn't timeout... */
  719         IFNET_STAT_INC(ifp, oerrors, 1);
  720         lprintf("X");
  721     } else {
  722         IFNET_STAT_INC(ifp, opackets, 1);
  723         IFNET_STAT_INC(ifp, obytes, m->m_pkthdr.len);
  724         if (ifp->if_bpf)
  725             lptap(ifp, m);
  726     }
  727 
  728     m_freem(m);
  729 
  730     if (ppb_rstr(ppbus) & LPIP_SHAKE) {
  731         lprintf("^");
  732         lp_intr(dev);
  733     }
  734 
  735     crit_exit();
  736     return 0;
  737 }
  738 
  739 /*
  740  * Because plip is a static device that always exists under any attached
  741  * ppbus device, and not scanned by the ppbus device, we need an identify
  742  * function to install the device.
  743  */
  744 static device_method_t lp_methods[] = {
  745         /* device interface */
  746         DEVMETHOD(device_identify,      bus_generic_identify),
  747         DEVMETHOD(device_probe,         lp_probe),
  748         DEVMETHOD(device_attach,        lp_attach),
  749 
  750         DEVMETHOD_END
  751 };
  752 
  753 static driver_t lp_driver = {
  754   "plip",
  755   lp_methods,
  756   sizeof(struct lp_data),
  757 };
  758 
  759 DECLARE_DUMMY_MODULE(if_plip);
  760 DRIVER_MODULE(if_plip, ppbus, lp_driver, lp_devclass, NULL, NULL);
  761 

Cache object: b6224a91d41d7adff25fff626f5b2e74


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