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 /* $NetBSD: if_plip.c,v 1.5 2004/02/10 21:55:38 jdolecek Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 1997 Poul-Henning Kamp
    5  * Copyright (c) 2003, 2004 Gary Thorpe <gathorpe@users.sourceforge.net>
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  *
   29  *      From Id: lpt.c,v 1.55.2.1 1996/11/12 09:08:38 phk Exp
   30  * FreeBSD: src/sys/dev/ppbus/if_plip.c,v 1.19.2.1 2000/05/24 00:20:57 n_hibma Exp
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __KERNEL_RCSID(0, "$NetBSD: if_plip.c,v 1.5 2004/02/10 21:55:38 jdolecek Exp $");
   35 
   36 /*
   37  * Parallel port TCP/IP interfaces added.  I looked at the driver from
   38  * MACH but this is a complete rewrite, and btw. incompatible, and it
   39  * should perform better too.  I have never run the MACH driver though.
   40  *
   41  * This driver sends two bytes (0x08, 0x00) in front of each packet,
   42  * to allow us to distinguish another format later.
   43  *
   44  * Now added an Linux/Crynwr compatibility mode which is enabled using
   45  * IF_LINK0 - Tim Wilkinson.
   46  *
   47  * TODO:
   48  *    Make HDLC/PPP mode, use IF_LLC1 to enable.
   49  *
   50  * Connect the two computers using a Laplink parallel cable to use this
   51  * feature:
   52  *
   53  *      +----------------------------------------+
   54  *      |A-name A-End   B-End   Descr.  Port/Bit |
   55  *      +----------------------------------------+
   56  *      |DATA0  2       15      Data    0/0x01   |
   57  *      |-ERROR 15      2               1/0x08   |
   58  *      +----------------------------------------+
   59  *      |DATA1  3       13      Data    0/0x02   |
   60  *      |+SLCT  13      3               1/0x10   |
   61  *      +----------------------------------------+
   62  *      |DATA2  4       12      Data    0/0x04   |
   63  *      |+PE    12      4               1/0x20   |
   64  *      +----------------------------------------+
   65  *      |DATA3  5       10      Strobe  0/0x08   |
   66  *      |-ACK   10      5               1/0x40   |
   67  *      +----------------------------------------+
   68  *      |DATA4  6       11      Data    0/0x10   |
   69  *      |BUSY   11      6               1/~0x80  |
   70  *      +----------------------------------------+
   71  *      |GND    18-25   18-25   GND     -        |
   72  *      +----------------------------------------+
   73  *
   74  * Expect transfer-rates up to 75 kbyte/sec.
   75  *
   76  * If GCC could correctly grok
   77  *      register int port asm("edx")
   78  * the code would be cleaner
   79  *
   80  * Poul-Henning Kamp <phk@freebsd.org>
   81  */
   82 
   83 /*
   84  * Update for ppbus, PLIP support only - Nicolas Souchu
   85  */ 
   86 
   87 #include "opt_inet.h"
   88 #include "opt_plip.h"
   89 #include "bpfilter.h"
   90 
   91 #include <sys/systm.h>
   92 #include <sys/param.h>
   93 #include <sys/proc.h>
   94 #include <sys/types.h>
   95 #include <sys/device.h>
   96 #include <sys/ioctl.h>
   97 #include <sys/malloc.h>
   98 #include <sys/mbuf.h>
   99 
  100 #include <net/if.h>
  101 #include <net/if_types.h>
  102 #include <net/netisr.h>
  103 
  104 #if NBPFILTER > 0
  105 #include <sys/time.h>
  106 #include <net/bpf.h>
  107 #endif
  108 
  109 #ifdef INET
  110 #include <netinet/in_var.h>
  111 /* #include <netinet/in.h> */
  112 #else
  113 #error Cannot config lp/plip without inet
  114 #endif
  115 
  116 #include <dev/ppbus/ppbus_base.h>
  117 #include <dev/ppbus/ppbus_device.h>
  118 #include <dev/ppbus/ppbus_io.h>
  119 #include <dev/ppbus/ppbus_var.h>
  120 
  121 #include <machine/types.h>
  122 #include <machine/intr.h>
  123 
  124 #ifndef LPMTU                   /* MTU for the lp# interfaces */
  125 #define LPMTU           1500
  126 #endif
  127 
  128 #ifndef LPMAXSPIN1              /* DELAY factor for the lp# interfaces */
  129 #define LPMAXSPIN1      8000    /* Spinning for remote intr to happen */
  130 #endif
  131 
  132 #ifndef LPMAXSPIN2              /* DELAY factor for the lp# interfaces */
  133 #define LPMAXSPIN2      500     /* Spinning for remote handshake to happen */
  134 #endif
  135 
  136 #ifndef LPMAXERRS               /* Max errors before !RUNNING */
  137 #define LPMAXERRS       100
  138 #endif
  139 
  140 #ifndef LPMAXRTRY
  141 #define LPMAXRTRY       100     /* If channel busy, retry LPMAXRTRY 
  142                                         consecutive times */
  143 #endif
  144 
  145 #define CLPIPHDRLEN     14      /* We send dummy ethernet addresses (two) + packet type in front of packet */
  146 #define CLPIP_SHAKE     0x80    /* This bit toggles between nibble reception */
  147 #define MLPIPHDRLEN     CLPIPHDRLEN
  148 
  149 #define LPIPHDRLEN      2       /* We send 0x08, 0x00 in front of packet */
  150 #define LPIP_SHAKE      0x40    /* This bit toggles between nibble reception */
  151 #if !defined(MLPIPHDRLEN) || LPIPHDRLEN > MLPIPHDRLEN
  152 #define MLPIPHDRLEN     LPIPHDRLEN
  153 #endif
  154 
  155 #define LPIPTBLSIZE     256     /* Size of octet translation table */
  156 
  157 #define LP_PRINTF       if (lpflag) printf
  158 
  159 #ifdef PLIP_DEBUG
  160 static int volatile lpflag = 1;
  161 #else
  162 static int volatile lpflag = 0;
  163 #endif
  164 
  165 /* Tx/Rsv 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 static u_char *ctxmith;
  171 #define ctxmitl (ctxmith+(1*LPIPTBLSIZE))
  172 #define ctrecvh (ctxmith+(2*LPIPTBLSIZE))
  173 #define ctrecvl (ctxmith+(3*LPIPTBLSIZE))
  174 static uint16_t lp_count = 0;
  175 
  176 /* Autoconf functions */
  177 static int lp_probe(struct device *, struct cfdata *, void *);
  178 static void lp_attach(struct device *, struct device *, void *);
  179 static int lp_detach(struct device *, int);
  180 
  181 /* Soft config data */
  182 struct lp_softc {
  183         struct ppbus_device_softc ppbus_dev;
  184         struct ifnet sc_if;
  185         u_char *sc_ifbuf;
  186         unsigned short sc_iferrs;
  187         unsigned short sc_xmit_rtry;
  188         u_int8_t sc_dev_ok; /* Zero means ok */
  189 };
  190 
  191 /* Autoconf structure */
  192 CFATTACH_DECL(plip, sizeof(struct lp_softc), lp_probe, lp_attach, lp_detach, 
  193         NULL);
  194 
  195 /* Functions for the lp interface */
  196 static void lpinittables(void);
  197 static void lpfreetables(void);
  198 static int lpioctl(struct ifnet *, u_long, caddr_t);
  199 static int lpoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
  200         struct rtentry *);
  201 static void lpstart(struct ifnet *);
  202 static void lp_intr(void *);
  203 
  204 
  205 static int
  206 lp_probe(struct device * parent, struct cfdata * match, void * aux)
  207 {
  208         struct ppbus_attach_args * args = aux;
  209         
  210         /* Fail if ppbus is not interrupt capable */ 
  211         if(args->capabilities & PPBUS_HAS_INTR)
  212                 return 1;
  213 
  214         printf("%s(%s): not an interrupt-driven port.\n", __func__, 
  215                 parent->dv_xname);
  216         return 0;
  217 }
  218 
  219 static void 
  220 lp_attach(struct device * parent, struct device * self, void * aux)
  221 {
  222         struct lp_softc * lp = (struct lp_softc *) self; 
  223         struct ifnet * ifp = &lp->sc_if;
  224 
  225         lp->sc_dev_ok = 0;
  226         lp->sc_ifbuf = NULL;
  227         lp->sc_iferrs = 0;
  228         lp->sc_xmit_rtry = 0;
  229 
  230         ifp->if_softc = self;
  231         strncpy(ifp->if_xname, self->dv_xname, IFNAMSIZ); 
  232         ifp->if_xname[IFNAMSIZ - 1] = '\0';
  233         ifp->if_mtu = LPMTU;
  234         ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST;
  235         ifp->if_ioctl = lpioctl;
  236         ifp->if_output = lpoutput;
  237         ifp->if_start = lpstart;
  238         ifp->if_type = IFT_PARA;
  239         ifp->if_hdrlen = 0;
  240         ifp->if_addrlen = 0;
  241         ifp->if_dlt = DLT_NULL;
  242         IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
  243         IFQ_SET_READY(&ifp->if_snd);
  244         if_attach(ifp);
  245         if_alloc_sadl(ifp);
  246 
  247 #if NBPFILTER > 0
  248         bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
  249 #endif
  250 
  251         if(lp_count++ == 0)
  252                 lpinittables();
  253         printf("\n");
  254 }
  255 
  256 static int
  257 lp_detach(struct device * self, int flags)
  258 {
  259         int error = 0;
  260         struct lp_softc * lp = (struct lp_softc *) self; 
  261         struct device * ppbus = self->dv_parent;
  262         
  263         if(lp->sc_dev_ok) {
  264                 if(!(flags & DETACH_QUIET))
  265                         LP_PRINTF("%s(%s): device not properly attached! "
  266                                 "Skipping detach....\n", __func__, 
  267                                 self->dv_xname);
  268                 return error;
  269         }
  270 
  271         /* If interface is up, bring it down and release ppbus */
  272         if(lp->sc_if.if_flags & IFF_RUNNING) {
  273                 ppbus_wctr(ppbus, 0x00);
  274                 if_detach(&lp->sc_if);
  275                 error = ppbus_remove_handler(ppbus, lp_intr);
  276                 if(error) {
  277                         if(!(flags & DETACH_QUIET))
  278                                 LP_PRINTF("%s(%s): unable to remove interrupt "
  279                                         "callback.\n", __func__, 
  280                                         self->dv_xname);
  281                         if(!(flags & DETACH_FORCE))
  282                                 return error;
  283                 }
  284                 error = ppbus_release_bus(ppbus, self, 0, 0);
  285                 if(error) {
  286                         if(!(flags & DETACH_QUIET))
  287                                 LP_PRINTF("%s(%s): error releasing bus %s.\n", 
  288                                         __func__, self->dv_xname, 
  289                                         ppbus->dv_xname);
  290                         if(!(flags & DETACH_FORCE))
  291                                 return error;
  292                 }
  293         }
  294 
  295         if(lp->sc_ifbuf)
  296                 free(lp->sc_ifbuf, M_DEVBUF);
  297 
  298         if(--lp_count == 0)
  299                 lpfreetables();
  300         return error;
  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 void 
  309 lpinittables (void)
  310 {
  311         int i;
  312 
  313         if (!txmith)
  314                 txmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_WAITOK);
  315 
  316         if (!ctxmith)
  317                 ctxmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_WAITOK);
  318 
  319         for(i = 0; i < LPIPTBLSIZE; i++) {
  320                 ctxmith[i] = (i & 0xF0) >> 4;
  321                 ctxmitl[i] = 0x10 | (i & 0x0F);
  322                 ctrecvh[i] = (i & 0x78) << 1;
  323                 ctrecvl[i] = (i & 0x78) >> 3;
  324         }
  325 
  326         for(i = 0; i < LPIPTBLSIZE; i++) {
  327                 txmith[i] = ((i & 0x80) >> 3) | ((i & 0x70) >> 4) | 0x08;
  328                 txmitl[i] = ((i & 0x08) << 1) | (i & 0x07);
  329                 trecvh[i] = ((~i) & 0x80) | ((i & 0x38) << 1);
  330                 trecvl[i] = (((~i) & 0x80) >> 4) | ((i & 0x38) >> 3);
  331         }
  332 }
  333 
  334 /* Free translation tables */
  335 static void 
  336 lpfreetables (void)
  337 {
  338         if (txmith)
  339                 free(txmith, M_DEVBUF);
  340         if (ctxmith)
  341                 free(ctxmith, M_DEVBUF);
  342         txmith = ctxmith = NULL;
  343 }
  344 
  345  
  346 /* Process an ioctl request. */
  347 static int
  348 lpioctl (struct ifnet *ifp, u_long cmd, caddr_t data)
  349 {
  350         struct device * dev = ifp->if_softc;
  351         struct device * ppbus = dev->dv_parent;
  352         struct lp_softc * sc = (struct lp_softc *) dev;
  353         struct ifaddr * ifa = (struct ifaddr *)data;
  354         struct ifreq * ifr = (struct ifreq *)data;
  355         u_char * ptr;
  356         int error, s;
  357 
  358         error = 0;
  359         s = splnet();
  360 
  361         if(sc->sc_dev_ok) {
  362                 LP_PRINTF("%s(%s): device not properly attached!", __func__, 
  363                         dev->dv_xname);
  364                 error = ENODEV;
  365                 goto end;
  366         }
  367         
  368         switch (cmd) {
  369 
  370         case SIOCSIFDSTADDR:
  371                 if (ifa->ifa_addr->sa_family != AF_INET)
  372                         error = EAFNOSUPPORT;
  373                 break;
  374         
  375         case SIOCSIFADDR:
  376                 if (ifa->ifa_addr->sa_family != AF_INET) {
  377                         error = EAFNOSUPPORT;
  378                         break;
  379                 }
  380                 ifp->if_flags |= IFF_UP;
  381         /* FALLTHROUGH */
  382         case SIOCSIFFLAGS:
  383                 if((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_UP) {
  384                         if((error = ppbus_request_bus(ppbus, dev, 0, 0)))
  385                                 break;
  386                         error = ppbus_set_mode(ppbus, PPBUS_COMPATIBLE, 0);
  387                         if(error)
  388                                 break;
  389                         
  390                         error = ppbus_add_handler(ppbus, lp_intr, dev);
  391                         if(error) {
  392                                 LP_PRINTF("%s(%s): unable to register interrupt"
  393                                         " callback.\n", __func__, 
  394                                         dev->dv_xname);
  395                                 ppbus_release_bus(ppbus, dev, 0, 0);
  396                                 break;
  397                         }
  398 
  399                         /* Allocate a buffer if necessary */
  400                         if(sc->sc_ifbuf == NULL) {
  401                                 sc->sc_ifbuf = malloc(sc->sc_if.if_mtu + 
  402                                         MLPIPHDRLEN, M_DEVBUF, M_NOWAIT);
  403                                 if (!sc->sc_ifbuf) {
  404                                         error = ENOBUFS;
  405                                         ppbus_release_bus(ppbus, dev, 0, 0);
  406                                         break;
  407                                 }
  408                         }
  409 
  410                         ppbus_wctr(ppbus, IRQENABLE);
  411                         ifp->if_flags |= IFF_RUNNING;
  412                 }
  413                 if((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_RUNNING) {
  414                         ppbus_remove_handler(ppbus, lp_intr);
  415                         error = ppbus_release_bus(ppbus, dev, 0, 0);
  416                         ifp->if_flags &= ~IFF_RUNNING;
  417                 }
  418                 /* Go quiescent */
  419                 ppbus_wdtr(ppbus, 0);
  420                 break;
  421 
  422         case SIOCSIFMTU:
  423                 if(sc->sc_if.if_mtu == ifr->ifr_mtu)
  424                         break;
  425                 ptr = sc->sc_ifbuf;
  426                 sc->sc_ifbuf = malloc(ifr->ifr_mtu+MLPIPHDRLEN, M_DEVBUF, 
  427                         M_NOWAIT);
  428                 if (!sc->sc_ifbuf) {
  429                         sc->sc_ifbuf = ptr;
  430                         error = ENOBUFS;
  431                         break;
  432                 }
  433                 if(ptr)
  434                         free(ptr,M_DEVBUF);
  435                 sc->sc_if.if_mtu = ifr->ifr_mtu;
  436                 break;
  437 
  438         case SIOCGIFMTU:
  439                 ifr->ifr_mtu = sc->sc_if.if_mtu;
  440                 break;
  441 
  442         case SIOCADDMULTI:
  443         case SIOCDELMULTI:
  444                 if (ifr == NULL) {
  445                         error = EAFNOSUPPORT;           /* XXX */
  446                         break;
  447                 }
  448                 switch (ifr->ifr_addr.sa_family) {
  449                 case AF_INET:
  450                         break;
  451                 default:
  452                         return EAFNOSUPPORT;
  453                 }
  454                 break;
  455 
  456         case SIOCGIFMEDIA:
  457                 /*
  458                  * No ifmedia support at this stage; maybe use it
  459                  * in future for eg. protocol selection.
  460                  */
  461         default:
  462                 LP_PRINTF("LP:ioctl(0x%lx)\n", cmd);
  463                 error = EINVAL;
  464         }
  465 
  466 end:
  467         splx(s);
  468         return error; 
  469 }
  470 
  471 static __inline int
  472 clpoutbyte (u_char byte, int spin, struct device * ppbus)
  473 {
  474         int s = spin;
  475         ppbus_wdtr(ppbus, ctxmitl[byte]);
  476         while (ppbus_rstr(ppbus) & CLPIP_SHAKE) {
  477                 if (--s == 0) {
  478                         return 1;
  479                 }
  480         }
  481         s = spin;
  482         ppbus_wdtr(ppbus, ctxmith[byte]);
  483         while (!(ppbus_rstr(ppbus) & CLPIP_SHAKE)) {
  484                 if (--s == 0) {
  485                         return 1;
  486                 }
  487         }
  488         return 0;
  489 }
  490 
  491 static __inline int
  492 clpinbyte (int spin, struct device * ppbus)
  493 {
  494         u_char c, cl;
  495         int s = spin;
  496 
  497         while(ppbus_rstr(ppbus) & CLPIP_SHAKE) {
  498                 if(!--s) {
  499                         return -1;
  500                 }
  501         }
  502         cl = ppbus_rstr(ppbus);
  503         ppbus_wdtr(ppbus, 0x10);
  504 
  505         s = spin;
  506         while(!(ppbus_rstr(ppbus) & CLPIP_SHAKE)) {
  507                 if(!--s) {
  508                         return -1;
  509                 }
  510         }
  511         c = ppbus_rstr(ppbus);
  512         ppbus_wdtr(ppbus, 0x00);
  513 
  514         return (ctrecvl[cl] | ctrecvh[c]);
  515 }
  516 
  517 #if NBPFILTER > 0
  518 static void
  519 lptap(struct ifnet *ifp, struct mbuf *m)
  520 {
  521         /*
  522          * Send a packet through bpf. We need to prepend the address family
  523          * as a four byte field. Cons up a dummy header to pacify bpf. This
  524          * is safe because bpf will only read from the mbuf (i.e., it won't
  525          * try to free it or keep a pointer to it).
  526          */
  527         u_int32_t af = AF_INET;
  528         struct mbuf m0;
  529         
  530         m0.m_next = m;
  531         m0.m_len = sizeof(u_int32_t);
  532         m0.m_data = (char *)&af;
  533         bpf_mtap(ifp->if_bpf, &m0);
  534 }
  535 #endif
  536 
  537 /* Soft interrupt handler called by hardware interrupt handler */
  538 static void
  539 lp_intr (void *arg)
  540 {
  541         struct device * dev = (struct device *)arg;
  542         struct device * ppbus = dev->dv_parent; 
  543         struct lp_softc * sc = (struct lp_softc *)dev;
  544         struct ifnet * ifp = &sc->sc_if;
  545         struct mbuf *top;
  546         int len, s, j;
  547         u_char *bp;
  548         u_char c, cl;
  549 
  550         s = splnet();
  551 
  552         /* Do nothing if device not properly attached */
  553         if(sc->sc_dev_ok) {
  554                 LP_PRINTF("%s(%s): device not properly attached!", __func__, 
  555                         dev->dv_xname);
  556                 goto done;
  557         }
  558 
  559         /* Do nothing if interface is not up */
  560         if((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
  561                 goto done;
  562 
  563         /* If other side is no longer transmitting, do nothing */
  564         if(!(ppbus_rstr(ppbus) & LPIP_SHAKE)) 
  565                 goto done;
  566 
  567         /* Disable interrupts until we finish */
  568         ppbus_wctr(ppbus, ~IRQENABLE);
  569 
  570         top = NULL;
  571         bp = sc->sc_ifbuf;
  572         /* Linux/crynwyr protocol receiving */
  573         if(ifp->if_flags & IFF_LINK0) {
  574                 /* Ack. the request */
  575                 ppbus_wdtr(ppbus, 0x01);
  576 
  577                 /* Get the packet length */
  578                 j = clpinbyte(LPMAXSPIN2, ppbus);
  579                 if(j == -1)
  580                         goto err;
  581                 len = j;
  582                 j = clpinbyte(LPMAXSPIN2, ppbus);
  583                 if(j == -1)
  584                         goto err;
  585                 len = len + (j << 8);
  586                 if(len > ifp->if_mtu + MLPIPHDRLEN)
  587                         goto err;
  588 
  589                 while(len--) {
  590                         j = clpinbyte(LPMAXSPIN2, ppbus);
  591                         if (j == -1) {
  592                                 goto err;
  593                         }
  594                         *bp++ = j;
  595                 }
  596                 /* Get and ignore checksum */
  597                 j = clpinbyte(LPMAXSPIN2, ppbus);
  598                 if(j == -1) {
  599                         goto err;
  600                 }
  601 
  602                 /* Return to idle state */
  603                 ppbus_wdtr(ppbus, 0);
  604                 len = bp - sc->sc_ifbuf;
  605                 if (len <= CLPIPHDRLEN)
  606                         goto err;
  607                 len -= CLPIPHDRLEN;
  608                 top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, ifp, NULL);
  609         }
  610         /* FreeBSD protocol receiving */
  611         else {
  612                 len = ifp->if_mtu + LPIPHDRLEN;
  613                 while(len--) {
  614                         cl = ppbus_rstr(ppbus);
  615                         ppbus_wdtr(ppbus, 0x08);
  616 
  617                         j = LPMAXSPIN2;
  618                         while((ppbus_rstr(ppbus) & LPIP_SHAKE)) {
  619                                 if(!--j) goto err;
  620                         }
  621 
  622                         c = ppbus_rstr(ppbus);
  623                         ppbus_wdtr(ppbus, 0);
  624 
  625                         *bp++= trecvh[cl] | trecvl[c];
  626 
  627                         j = LPMAXSPIN2;
  628                         while(!((cl=ppbus_rstr(ppbus)) & LPIP_SHAKE)) {
  629                                 if(cl != c &&
  630                                         (((cl = ppbus_rstr(ppbus)) ^ 0xb8) & 
  631                                         0xf8) == (c & 0xf8))
  632                                         goto end;
  633                                 if(!--j) goto err;
  634                         }
  635                 }
  636 
  637 end:
  638                 len = bp - sc->sc_ifbuf;
  639                 if(len <= LPIPHDRLEN)
  640                         goto err;
  641                 len -= LPIPHDRLEN;
  642                 top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, ifp, NULL);
  643         }
  644 
  645         /* Do nothing if mbuf was not created or the queue is full */
  646         if((top == NULL) || (IF_QFULL(&ipintrq))) {
  647                 IF_DROP(&ipintrq);
  648                 ifp->if_iqdrops++;
  649                 LP_PRINTF("DROP");
  650                 goto err;
  651         }
  652 #if NBPFILTER > 0
  653         if(ifp->if_bpf)
  654                 lptap(ifp, top);
  655 #endif
  656         IF_ENQUEUE(&ipintrq, top);
  657         schednetisr(NETISR_IP);
  658         ifp->if_ipackets++;
  659         ifp->if_ibytes += len;
  660         sc->sc_iferrs = 0;
  661 
  662         goto done;
  663 
  664 err:
  665         /* Return to idle state */
  666         ppbus_wdtr(ppbus, 0);
  667         ifp->if_ierrors++;
  668         sc->sc_iferrs++;
  669         LP_PRINTF("R");
  670         /* Disable interface if there are too many errors */ 
  671         if(sc->sc_iferrs > LPMAXERRS) {
  672                 printf("%s: Too many consecutive errors, going off-line.\n", 
  673                         dev->dv_xname);
  674                 ppbus_wctr(ppbus, ~IRQENABLE);
  675                 if_down(ifp);
  676                 sc->sc_iferrs = 0;
  677         }
  678 
  679 done:
  680         /* Re-enable interrupts */
  681         ppbus_wctr(ppbus, IRQENABLE);
  682         /* If interface is not active, send some packets */
  683         if((ifp->if_flags & IFF_OACTIVE) == 0) 
  684                 lpstart(ifp);
  685         splx(s);
  686         return;
  687 }
  688 
  689 static __inline int
  690 lpoutbyte(u_char byte, int spin, struct device * ppbus)
  691 {
  692         int s = spin;
  693         ppbus_wdtr(ppbus, txmith[byte]);
  694         while(!(ppbus_rstr(ppbus) & LPIP_SHAKE)) {
  695                 if(--s == 0)
  696                         return 1;
  697         }
  698         s = spin;
  699         ppbus_wdtr(ppbus, txmitl[byte]);
  700         while(ppbus_rstr(ppbus) & LPIP_SHAKE) {
  701                 if(--s == 0)
  702                         return 1;
  703         }
  704         return 0;
  705 }
  706 
  707 /* Queue a packet for delivery */
  708 static int
  709 lpoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 
  710         struct rtentry *rt)
  711 {
  712         struct device * dev = ifp->if_softc;
  713         struct device * ppbus = dev->dv_parent;
  714         struct lp_softc * sc = (struct lp_softc *) dev;
  715         ALTQ_DECL(struct altq_pktattr pktattr;)
  716         int err;
  717         int s;
  718 
  719         s = splnet();
  720 
  721         if(sc->sc_dev_ok) {
  722                 LP_PRINTF("%s(%s): device not properly attached!", __func__, 
  723                         dev->dv_xname);
  724                 err = ENODEV;
  725                 goto endoutput;
  726         }
  727         
  728         if((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
  729                 err = ENETDOWN;
  730                 goto endoutput;
  731         }
  732         
  733         /* Only support INET */
  734         if(dst->sa_family != AF_INET) {
  735                 LP_PRINTF("%s: af%d not supported\n", ifp->if_xname,
  736                     dst->sa_family);
  737                 ifp->if_noproto++;
  738                 err = EAFNOSUPPORT;
  739                 goto endoutput;
  740         }
  741         
  742         IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr);
  743         IFQ_ENQUEUE(&ifp->if_snd, m, dst->sa_family, err);
  744         if(err == 0) {
  745                 if((ifp->if_flags & IFF_OACTIVE) == 0)
  746                         lpstart(ifp);
  747         }
  748         else {
  749                 ifp->if_oerrors++;
  750                 sc->sc_iferrs++;
  751                 LP_PRINTF("Q");
  752 
  753                 /* Disable interface if there are too many errors */ 
  754                 if(sc->sc_iferrs > LPMAXERRS) {
  755                         printf("%s: Too many errors, going off-line.\n", 
  756                                 dev->dv_xname);
  757                         ppbus_wctr(ppbus, ~IRQENABLE);
  758                         if_down(ifp);
  759                         sc->sc_iferrs = 0;
  760                 }
  761         }
  762 
  763 endoutput:
  764         if((err != 0) && (err != ENOBUFS))
  765                 m_freem(m);
  766         splx(s);
  767         return err;
  768 }
  769 
  770 /* Send routine: send packets over PLIP cable. Call at splnet(). */
  771 void
  772 lpstart(struct ifnet * ifp) 
  773 {
  774         struct lp_softc * lp = ifp->if_softc;
  775         struct device * dev = ifp->if_softc;
  776         struct device * ppbus = dev->dv_parent;
  777         struct mbuf * mm;
  778         struct mbuf * m;
  779         u_char * cp;
  780         int err, i, len, spin, count;
  781         u_char str, chksum;
  782 
  783         if(lp->sc_dev_ok) {
  784                 LP_PRINTF("%s(%s): device not properly attached!", __func__, 
  785                         dev->dv_xname);
  786                 return;
  787         }
  788         
  789         if((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
  790                 return;
  791         }
  792 
  793         ifp->if_flags |= IFF_OACTIVE;
  794 
  795         /* Go quiescent */
  796         ppbus_wdtr(ppbus, 0);
  797 
  798         /* Output loop */
  799         for(;;) {
  800                 /* Check if there are packets to send */
  801                 if(IFQ_IS_EMPTY(&ifp->if_snd)) {
  802                         goto final;
  803                 }
  804                 /* Try to send a packet, dequeue it later if successful */
  805                 IFQ_POLL(&ifp->if_snd, m);
  806                 if(m == NULL)
  807                         goto final;
  808 
  809                 str = ppbus_rstr(ppbus);
  810                 /* Wait until other side is not transmitting */
  811                 if((str & LPIP_SHAKE) || 
  812                         ((ifp->if_flags & IFF_LINK0) && !(str & CLPIP_SHAKE))) {
  813                         LP_PRINTF("&");
  814                         if(++lp->sc_xmit_rtry > LPMAXRTRY) {
  815                                 printf("%s: Too many retries while channel "
  816                                         "busy, going off-line.\n", 
  817                                         dev->dv_xname);
  818                                 ppbus_wctr(ppbus, ~IRQENABLE);
  819                                 if_down(ifp);
  820                                 lp->sc_xmit_rtry = 0;
  821                         }
  822                         goto final;
  823                 }
  824                 lp->sc_xmit_rtry = 0;
  825 
  826                 /* Disable interrupt generation */
  827                 ppbus_wctr(ppbus, ~IRQENABLE);
  828                 
  829                 err = 1;
  830 
  831                 /* Output packet for Linux/crynwyr compatible protocol */
  832                 if(ifp->if_flags & IFF_LINK0) {
  833                         /* Calculate packet length */
  834                         count = 14;             /* Ethernet header len */
  835                         for(mm = m; mm; mm = mm->m_next) {
  836                                 count += mm->m_len;
  837                         }
  838 
  839                         /* Alert other end to pending packet */
  840                         spin = LPMAXSPIN1;
  841                         ppbus_wdtr(ppbus, 0x08);
  842                         while((ppbus_rstr(ppbus) & 0x08) == 0) {
  843                                 if (--spin == 0) {
  844                                         goto nend;
  845                                 }
  846                         }
  847 
  848                         if(clpoutbyte(count & 0xFF, LPMAXSPIN1, ppbus))
  849                                 goto nend;
  850                         if(clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, ppbus))
  851                                 goto nend;
  852 
  853                         /* Send dummy ethernet header */
  854                         chksum = 0;
  855                         for(i = 0; i < 12; i++) {
  856                                 if(clpoutbyte(i, LPMAXSPIN1, ppbus))
  857                                         goto nend;
  858                                 chksum += i;
  859                         }
  860 
  861                         if(clpoutbyte(0x08, LPMAXSPIN1, ppbus))
  862                                 goto nend;
  863                         if(clpoutbyte(0x00, LPMAXSPIN1, ppbus))
  864                                 goto nend;
  865                         chksum += 0x08 + 0x00;          /* Add into checksum */
  866 
  867                         mm = m;
  868                         do {
  869                                 cp = mtod(mm, u_char *);
  870                                 len = mm->m_len;
  871                                 while(len--) {
  872                                         if(clpoutbyte(*cp, LPMAXSPIN2, ppbus))
  873                                                 goto nend;
  874                                         chksum += *cp++;
  875                                 }
  876                         } while ((mm = mm->m_next));
  877 
  878                         /* Send checksum */
  879                         if(clpoutbyte(chksum, LPMAXSPIN2, ppbus))
  880                                 goto nend;
  881 
  882                         /* No errors */
  883                         err = 0;
  884                         /* Go quiescent */
  885                         ppbus_wdtr(ppbus, 0);
  886                 }
  887                 /* Output packet for FreeBSD compatible protocol */
  888                 else {
  889                         /* We need a sensible value if we abort */
  890                         cp = NULL;
  891 
  892                         if(lpoutbyte(0x08, LPMAXSPIN1, ppbus))
  893                                 goto end;
  894                         if(lpoutbyte(0x00, LPMAXSPIN2, ppbus))
  895                                 goto end;
  896 
  897                         mm = m;
  898                         do {
  899                                 cp = mtod(mm,u_char *);
  900                                 len = mm->m_len;
  901                                 while(len--)
  902                                         if(lpoutbyte(*cp++, LPMAXSPIN2, ppbus))
  903                                                 goto end;
  904                         } while ((mm = mm->m_next));
  905 
  906                         /* no errors were encountered */
  907                         err = 0;
  908 
  909 end:
  910                         if(cp)
  911                                 ppbus_wdtr(ppbus, txmitl[*(--cp)] ^ 0x17);
  912                         else
  913                                 ppbus_wdtr(ppbus, txmitl['\0'] ^ 0x17);
  914                 }
  915 
  916 nend:
  917                 /* Re-enable interrupt generation */
  918                 ppbus_wctr(ppbus, IRQENABLE);
  919 
  920                 if(err) {
  921                         /* Go quiescent */
  922                         ppbus_wdtr(ppbus, 0);
  923         
  924                         ifp->if_oerrors++;
  925                         lp->sc_iferrs++;
  926                         LP_PRINTF("X");
  927 
  928                         /* Disable interface if there are too many errors */ 
  929                         if(lp->sc_iferrs > LPMAXERRS) {
  930                                 printf("%s: Too many errors, going off-line.\n",
  931                                         dev->dv_xname);
  932                                 ppbus_wctr(ppbus, ~IRQENABLE);
  933                                 if_down(ifp);
  934                                 lp->sc_iferrs = 0;
  935                                 goto final;
  936                         }
  937                 }
  938                 else {
  939                         /* Dequeue packet on success */
  940                         IFQ_DEQUEUE(&ifp->if_snd, m);
  941 #if NBPFILTER > 0
  942                         if(ifp->if_bpf)
  943                                 lptap(ifp, m);
  944 #endif
  945                         ifp->if_opackets++;
  946                         ifp->if_obytes += m->m_pkthdr.len;
  947                         m_freem(m);
  948                 }
  949         }
  950 
  951 final:
  952         ifp->if_flags &= ~IFF_OACTIVE;
  953         return;
  954 }

Cache object: 9b73031dfbab87e1796c84560da26332


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