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/isa/if_eg.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_eg.c,v 1.62 2003/10/30 01:58:17 simonb Exp $        */
    2 
    3 /*
    4  * Copyright (c) 1993 Dean Huxley <dean@fsa.ca>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. All advertising materials mentioning features or use of this software
   16  *    must display the following acknowledgement:
   17  *      This product includes software developed by Dean Huxley.
   18  * 4. The name of Dean Huxley may not be used to endorse or promote products
   19  *    derived from this software without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 /*
   33  * Support for 3Com 3c505 Etherlink+ card.
   34  */
   35 
   36 /*
   37  * To do:
   38  * - multicast
   39  * - promiscuous
   40  */
   41 
   42 #include <sys/cdefs.h>
   43 __KERNEL_RCSID(0, "$NetBSD: if_eg.c,v 1.62 2003/10/30 01:58:17 simonb Exp $");
   44 
   45 #include "opt_inet.h"
   46 #include "opt_ns.h"
   47 #include "bpfilter.h"
   48 #include "rnd.h"
   49 
   50 #include <sys/param.h>
   51 #include <sys/systm.h>
   52 #include <sys/mbuf.h>
   53 #include <sys/socket.h>
   54 #include <sys/ioctl.h>
   55 #include <sys/errno.h>
   56 #include <sys/syslog.h>
   57 #include <sys/select.h>
   58 #include <sys/device.h>
   59 #if NRND > 0
   60 #include <sys/rnd.h>
   61 #endif
   62 
   63 #include <net/if.h>
   64 #include <net/if_dl.h>
   65 #include <net/if_types.h>
   66 
   67 #include <net/if_ether.h>
   68 
   69 #ifdef INET
   70 #include <netinet/in.h>
   71 #include <netinet/in_systm.h>
   72 #include <netinet/in_var.h>
   73 #include <netinet/ip.h>
   74 #include <netinet/if_inarp.h>
   75 #endif
   76 
   77 #ifdef NS
   78 #include <netns/ns.h>
   79 #include <netns/ns_if.h>
   80 #endif
   81 
   82 #if NBPFILTER > 0
   83 #include <net/bpf.h>
   84 #include <net/bpfdesc.h>
   85 #endif
   86 
   87 #include <machine/cpu.h>
   88 #include <machine/intr.h>
   89 #include <machine/bus.h>
   90 
   91 #include <dev/isa/isavar.h>
   92 #include <dev/isa/if_egreg.h>
   93 #include <dev/isa/elink.h>
   94 
   95 /* for debugging convenience */
   96 #ifdef EGDEBUG
   97 #define DPRINTF(x) printf x
   98 #else
   99 #define DPRINTF(x)
  100 #endif
  101 
  102 #define EG_INLEN        10
  103 #define EG_BUFLEN       0x0670
  104 
  105 #define EG_PCBLEN 64
  106 
  107 /*
  108  * Ethernet software status per interface.
  109  */
  110 struct eg_softc {
  111         struct device sc_dev;
  112         void *sc_ih;
  113         struct ethercom sc_ethercom;    /* Ethernet common part */
  114         bus_space_tag_t sc_iot;         /* bus space identifier */
  115         bus_space_handle_t sc_ioh;      /* i/o handle */
  116         u_int8_t eg_rom_major;          /* Cards ROM version (major number) */ 
  117         u_int8_t eg_rom_minor;          /* Cards ROM version (minor number) */ 
  118         short    eg_ram;                /* Amount of RAM on the card */
  119         u_int8_t eg_pcb[EG_PCBLEN];     /* Primary Command Block buffer */
  120         u_int8_t eg_incount;            /* Number of buffers currently used */
  121         caddr_t eg_inbuf;               /* Incoming packet buffer */
  122         caddr_t eg_outbuf;              /* Outgoing packet buffer */
  123 
  124 #if NRND > 0
  125         rndsource_element_t rnd_source;
  126 #endif
  127 };
  128 
  129 int egprobe __P((struct device *, struct cfdata *, void *));
  130 void egattach __P((struct device *, struct device *, void *));
  131 
  132 CFATTACH_DECL(eg, sizeof(struct eg_softc),
  133     egprobe, egattach, NULL, NULL);
  134 
  135 int egintr __P((void *));
  136 void eginit __P((struct eg_softc *));
  137 int egioctl __P((struct ifnet *, u_long, caddr_t));
  138 void egrecv __P((struct eg_softc *));
  139 void egstart __P((struct ifnet *));
  140 void egwatchdog __P((struct ifnet *));
  141 void egreset __P((struct eg_softc *));
  142 void egread __P((struct eg_softc *, caddr_t, int));
  143 struct mbuf *egget __P((struct eg_softc *, caddr_t, int));
  144 void egstop __P((struct eg_softc *));
  145 
  146 static inline void egprintpcb __P((u_int8_t *));
  147 static inline void egprintstat __P((u_char));
  148 static int egoutPCB __P((bus_space_tag_t, bus_space_handle_t, u_int8_t));
  149 static int egreadPCBstat __P((bus_space_tag_t, bus_space_handle_t, u_int8_t));
  150 static int egreadPCBready __P((bus_space_tag_t, bus_space_handle_t));
  151 static int egwritePCB __P((bus_space_tag_t, bus_space_handle_t, u_int8_t *));
  152 static int egreadPCB __P((bus_space_tag_t, bus_space_handle_t, u_int8_t *));
  153 
  154 /*
  155  * Support stuff
  156  */
  157         
  158 static inline void
  159 egprintpcb(pcb)
  160         u_int8_t *pcb;
  161 {
  162         int i;
  163         
  164         for (i = 0; i < pcb[1] + 2; i++)
  165                 DPRINTF(("pcb[%2d] = %x\n", i, pcb[i]));
  166 }
  167 
  168 
  169 static inline void
  170 egprintstat(b)
  171         u_char b;
  172 {
  173         DPRINTF(("%s %s %s %s %s %s %s\n", 
  174                  (b & EG_STAT_HCRE)?"HCRE":"",
  175                  (b & EG_STAT_ACRF)?"ACRF":"",
  176                  (b & EG_STAT_DIR )?"DIR ":"",
  177                  (b & EG_STAT_DONE)?"DONE":"",
  178                  (b & EG_STAT_ASF3)?"ASF3":"",
  179                  (b & EG_STAT_ASF2)?"ASF2":"",
  180                  (b & EG_STAT_ASF1)?"ASF1":""));
  181 }
  182 
  183 static int
  184 egoutPCB(iot, ioh, b)
  185         bus_space_tag_t iot;
  186         bus_space_handle_t ioh;
  187         u_int8_t b;
  188 {
  189         int i;
  190 
  191         for (i=0; i < 4000; i++) {
  192                 if (bus_space_read_1(iot, ioh, EG_STATUS) & EG_STAT_HCRE) {
  193                         bus_space_write_1(iot, ioh, EG_COMMAND, b);
  194                         return 0;
  195                 }
  196                 delay(10);
  197         }
  198         DPRINTF(("egoutPCB failed\n"));
  199         return 1;
  200 }
  201         
  202 static int
  203 egreadPCBstat(iot, ioh, statb)
  204         bus_space_tag_t iot;
  205         bus_space_handle_t ioh;
  206         u_int8_t statb;
  207 {
  208         int i;
  209 
  210         for (i=0; i < 5000; i++) {
  211                 if ((bus_space_read_1(iot, ioh, EG_STATUS) &
  212                     EG_PCB_STAT) != EG_PCB_NULL) 
  213                         break;
  214                 delay(10);
  215         }
  216         if ((bus_space_read_1(iot, ioh, EG_STATUS) & EG_PCB_STAT) == statb) 
  217                 return 0;
  218         return 1;
  219 }
  220 
  221 static int
  222 egreadPCBready(iot, ioh)
  223         bus_space_tag_t iot;
  224         bus_space_handle_t ioh;
  225 {
  226         int i;
  227 
  228         for (i=0; i < 10000; i++) {
  229                 if (bus_space_read_1(iot, ioh, EG_STATUS) & EG_STAT_ACRF)
  230                         return 0;
  231                 delay(5);
  232         }
  233         DPRINTF(("PCB read not ready\n"));
  234         return 1;
  235 }
  236         
  237 static int
  238 egwritePCB(iot, ioh, pcb)
  239         bus_space_tag_t iot;
  240         bus_space_handle_t ioh;
  241         u_int8_t *pcb;
  242 {
  243         int i;
  244         u_int8_t len;
  245 
  246         bus_space_write_1(iot, ioh, EG_CONTROL,
  247             (bus_space_read_1(iot, ioh, EG_CONTROL) & ~EG_PCB_STAT) | EG_PCB_NULL);
  248 
  249         len = pcb[1] + 2;
  250         for (i = 0; i < len; i++)
  251                 egoutPCB(iot, ioh, pcb[i]);
  252 
  253         for (i=0; i < 4000; i++) {
  254                 if (bus_space_read_1(iot, ioh, EG_STATUS) & EG_STAT_HCRE)
  255                         break;
  256                 delay(10);
  257         }
  258 
  259         bus_space_write_1(iot, ioh, EG_CONTROL,
  260             (bus_space_read_1(iot, ioh, EG_CONTROL) & ~EG_PCB_STAT) | EG_PCB_DONE);
  261 
  262         egoutPCB(iot, ioh, len);
  263 
  264         if (egreadPCBstat(iot, ioh, EG_PCB_ACCEPT))
  265                 return 1;
  266         return 0;
  267 }       
  268         
  269 static int
  270 egreadPCB(iot, ioh, pcb)
  271         bus_space_tag_t iot;
  272         bus_space_handle_t ioh;
  273         u_int8_t *pcb;
  274 {
  275         int i;
  276 
  277         bus_space_write_1(iot, ioh, EG_CONTROL,
  278             (bus_space_read_1(iot, ioh, EG_CONTROL) & ~EG_PCB_STAT) | EG_PCB_NULL);
  279 
  280         memset(pcb, 0, EG_PCBLEN);
  281 
  282         if (egreadPCBready(iot, ioh))
  283                 return 1;
  284 
  285         pcb[0] = bus_space_read_1(iot, ioh, EG_COMMAND);
  286 
  287         if (egreadPCBready(iot, ioh))
  288                 return 1;
  289 
  290         pcb[1] = bus_space_read_1(iot, ioh, EG_COMMAND);
  291 
  292         if (pcb[1] > 62) {
  293                 DPRINTF(("len %d too large\n", pcb[1]));
  294                 return 1;
  295         }
  296 
  297         for (i = 0; i < pcb[1]; i++) {
  298                 if (egreadPCBready(iot, ioh))
  299                         return 1;
  300                 pcb[2+i] = bus_space_read_1(iot, ioh, EG_COMMAND);
  301         }
  302         if (egreadPCBready(iot, ioh))
  303                 return 1;
  304         if (egreadPCBstat(iot, ioh, EG_PCB_DONE))
  305                 return 1;
  306         if (bus_space_read_1(iot, ioh, EG_COMMAND) != pcb[1] + 2) {
  307                 DPRINTF(("%d != %d\n", b, pcb[1] + 2));
  308                 return 1;
  309         }
  310 
  311         bus_space_write_1(iot, ioh, EG_CONTROL,
  312             (bus_space_read_1(iot, ioh, EG_CONTROL) &
  313             ~EG_PCB_STAT) | EG_PCB_ACCEPT);
  314 
  315         return 0;
  316 }       
  317 
  318 /*
  319  * Real stuff
  320  */
  321 
  322 int
  323 egprobe(parent, match, aux)
  324         struct device *parent;
  325         struct cfdata *match;
  326         void *aux;
  327 {
  328         struct isa_attach_args *ia = aux;
  329         bus_space_tag_t iot = ia->ia_iot;
  330         bus_space_handle_t ioh;
  331         int i, rval;
  332         static u_int8_t pcb[EG_PCBLEN];
  333 
  334         rval = 0;
  335 
  336         if (ia->ia_nio < 1)
  337                 return (0);
  338         if (ia->ia_nirq < 1)
  339                 return (0);
  340 
  341         if (ISA_DIRECT_CONFIG(ia))
  342                 return (0);
  343 
  344         /* Disallow wildcarded i/o address. */
  345         if (ia->ia_io[0].ir_addr == ISACF_PORT_DEFAULT)
  346                 return (0);
  347 
  348         /* Disallow wildcarded IRQ. */
  349         if (ia->ia_irq[0].ir_irq == ISACF_IRQ_DEFAULT)
  350                 return (0);
  351 
  352         if ((ia->ia_io[0].ir_addr & ~0x07f0) != 0) {
  353                 DPRINTF(("Weird iobase %x\n", ia->ia_io[0].ir_addr));
  354                 return 0;
  355         }
  356 
  357         /* Map i/o space. */
  358         if (bus_space_map(iot, ia->ia_io[0].ir_addr, 0x08, 0, &ioh)) {
  359                 DPRINTF(("egprobe: can't map i/o space in probe\n"));
  360                 return 0;
  361         }
  362 
  363         /* hard reset card */
  364         bus_space_write_1(iot, ioh, EG_CONTROL, EG_CTL_RESET); 
  365         bus_space_write_1(iot, ioh, EG_CONTROL, 0);
  366         for (i = 0; i < 5000; i++) {
  367                 delay(1000);
  368                 if ((bus_space_read_1(iot, ioh, EG_STATUS) &
  369                     EG_PCB_STAT) == EG_PCB_NULL) 
  370                         break;
  371         }
  372         if ((bus_space_read_1(iot, ioh, EG_STATUS) & EG_PCB_STAT) != EG_PCB_NULL) {
  373                 DPRINTF(("egprobe: Reset failed\n"));
  374                 goto out;
  375         }
  376         pcb[0] = EG_CMD_GETINFO; /* Get Adapter Info */
  377         pcb[1] = 0;
  378         if (egwritePCB(iot, ioh, pcb) != 0)
  379                 goto out;
  380 
  381         if ((egreadPCB(iot, ioh, pcb) != 0) ||
  382             pcb[0] != EG_RSP_GETINFO || /* Get Adapter Info Response */
  383             pcb[1] != 0x0a) {
  384                 egprintpcb(pcb);
  385                 goto out;
  386         }
  387 
  388         ia->ia_nio = 1;
  389         ia->ia_io[0].ir_size = 0x08;
  390 
  391         ia->ia_nirq = 1;
  392 
  393         ia->ia_niomem = 0;
  394         ia->ia_ndrq = 0;
  395 
  396         rval = 1;
  397 
  398  out:
  399         bus_space_unmap(iot, ioh, 0x08);
  400         return rval;
  401 }
  402 
  403 void
  404 egattach(parent, self, aux)
  405         struct device *parent, *self;
  406         void *aux;
  407 {
  408         struct eg_softc *sc = (void *)self;
  409         struct isa_attach_args *ia = aux;
  410         bus_space_tag_t iot = ia->ia_iot;
  411         bus_space_handle_t ioh;
  412         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  413         u_int8_t myaddr[ETHER_ADDR_LEN];
  414 
  415         printf("\n");
  416 
  417         /* Map i/o space. */
  418         if (bus_space_map(iot, ia->ia_io[0].ir_addr, 0x08, 0, &ioh)) {
  419                 printf("%s: can't map i/o space\n", self->dv_xname);
  420                 return;
  421         }
  422 
  423         sc->sc_iot = iot;
  424         sc->sc_ioh = ioh;
  425 
  426         sc->eg_pcb[0] = EG_CMD_GETINFO; /* Get Adapter Info */
  427         sc->eg_pcb[1] = 0;
  428         if (egwritePCB(iot, ioh, sc->eg_pcb) != 0) {
  429                 printf("%s: error requesting adapter info\n", self->dv_xname);
  430                 return;
  431         }
  432         if (egreadPCB(iot, ioh, sc->eg_pcb) != 0) {
  433                 egprintpcb(sc->eg_pcb);
  434                 printf("%s: error reading adapter info\n", self->dv_xname);
  435                 return;
  436         }
  437 
  438         if (sc->eg_pcb[0] != EG_RSP_GETINFO || /* Get Adapter Info Response */
  439             sc->eg_pcb[1] != 0x0a) {
  440                 egprintpcb(sc->eg_pcb);
  441                 printf("%s: bogus adapter info\n", self->dv_xname);
  442                 return;
  443         }
  444 
  445         sc->eg_rom_major = sc->eg_pcb[3];
  446         sc->eg_rom_minor = sc->eg_pcb[2];
  447         sc->eg_ram = sc->eg_pcb[6] | (sc->eg_pcb[7] << 8);
  448 
  449         egstop(sc);
  450 
  451         sc->eg_pcb[0] = EG_CMD_GETEADDR; /* Get Station address */
  452         sc->eg_pcb[1] = 0;
  453         if (egwritePCB(iot, ioh, sc->eg_pcb) != 0) {
  454                 printf("%s: can't send Get Station Address\n", self->dv_xname);
  455                 return;
  456         }       
  457         if (egreadPCB(iot, ioh, sc->eg_pcb) != 0) {
  458                 printf("%s: can't read station address\n", self->dv_xname);
  459                 egprintpcb(sc->eg_pcb);
  460                 return;
  461         }
  462 
  463         /* check Get station address response */
  464         if (sc->eg_pcb[0] != EG_RSP_GETEADDR || sc->eg_pcb[1] != 0x06) { 
  465                 printf("%s: card responded with garbage (1)\n",
  466                     self->dv_xname);
  467                 egprintpcb(sc->eg_pcb);
  468                 return;
  469         }
  470         memcpy(myaddr, &sc->eg_pcb[2], ETHER_ADDR_LEN);
  471 
  472         printf("%s: ROM v%d.%02d %dk address %s\n", self->dv_xname,
  473             sc->eg_rom_major, sc->eg_rom_minor, sc->eg_ram,
  474             ether_sprintf(myaddr));
  475 
  476         sc->eg_pcb[0] = EG_CMD_SETEADDR; /* Set station address */
  477         if (egwritePCB(iot, ioh, sc->eg_pcb) != 0) {
  478                 printf("%s: can't send Set Station Address\n", self->dv_xname);
  479                 return;
  480         }
  481         if (egreadPCB(iot, ioh, sc->eg_pcb) != 0) {
  482                 printf("%s: can't read Set Station Address status\n",
  483                     self->dv_xname);
  484                 egprintpcb(sc->eg_pcb);
  485                 return;
  486         }
  487         if (sc->eg_pcb[0] != EG_RSP_SETEADDR || sc->eg_pcb[1] != 0x02 ||
  488             sc->eg_pcb[2] != 0 || sc->eg_pcb[3] != 0) {
  489                 printf("%s: card responded with garbage (2)\n",
  490                     self->dv_xname);
  491                 egprintpcb(sc->eg_pcb);
  492                 return;
  493         }
  494 
  495         /* Initialize ifnet structure. */
  496         strcpy(ifp->if_xname, sc->sc_dev.dv_xname);
  497         ifp->if_softc = sc;
  498         ifp->if_start = egstart;
  499         ifp->if_ioctl = egioctl;
  500         ifp->if_watchdog = egwatchdog;
  501         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
  502         IFQ_SET_READY(&ifp->if_snd);
  503 
  504         /* Now we can attach the interface. */
  505         if_attach(ifp);
  506         ether_ifattach(ifp, myaddr);
  507         
  508         sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq,
  509             IST_EDGE, IPL_NET, egintr, sc);
  510 
  511 #if NRND > 0
  512         rnd_attach_source(&sc->rnd_source, sc->sc_dev.dv_xname,
  513                           RND_TYPE_NET, 0);
  514 #endif
  515 }
  516 
  517 void
  518 eginit(sc)
  519         struct eg_softc *sc;
  520 {
  521         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  522         bus_space_tag_t iot = sc->sc_iot;
  523         bus_space_handle_t ioh = sc->sc_ioh;
  524 
  525         /* soft reset the board */
  526         bus_space_write_1(iot, ioh, EG_CONTROL, EG_CTL_FLSH);
  527         delay(100);
  528         bus_space_write_1(iot, ioh, EG_CONTROL, EG_CTL_ATTN);
  529         delay(100);
  530         bus_space_write_1(iot, ioh, EG_CONTROL, 0);
  531         delay(200);
  532 
  533         sc->eg_pcb[0] = EG_CMD_CONFIG82586; /* Configure 82586 */
  534         sc->eg_pcb[1] = 2;
  535         sc->eg_pcb[2] = 3; /* receive broadcast & multicast */
  536         sc->eg_pcb[3] = 0;
  537         if (egwritePCB(iot, ioh, sc->eg_pcb) != 0)
  538                 printf("%s: can't send Configure 82586\n",
  539                     sc->sc_dev.dv_xname);
  540 
  541         if (egreadPCB(iot, ioh, sc->eg_pcb) != 0) {
  542                 printf("%s: can't read Configure 82586 status\n",
  543                     sc->sc_dev.dv_xname);
  544                 egprintpcb(sc->eg_pcb);
  545         } else if (sc->eg_pcb[2] != 0 || sc->eg_pcb[3] != 0)
  546                 printf("%s: configure card command failed\n",
  547                     sc->sc_dev.dv_xname);
  548 
  549         if (sc->eg_inbuf == NULL) {
  550                 sc->eg_inbuf = malloc(EG_BUFLEN, M_TEMP, M_NOWAIT);
  551                 if (sc->eg_inbuf == NULL) {
  552                         printf("%s: can't allocate inbuf\n",
  553                             sc->sc_dev.dv_xname);
  554                         panic("eginit");
  555                 }
  556         }
  557         sc->eg_incount = 0;
  558 
  559         if (sc->eg_outbuf == NULL) {
  560                 sc->eg_outbuf = malloc(EG_BUFLEN, M_TEMP, M_NOWAIT);
  561                 if (sc->eg_outbuf == NULL) {
  562                         printf("%s: can't allocate outbuf\n",
  563                             sc->sc_dev.dv_xname);
  564                         panic("eginit");
  565                 }
  566         }
  567 
  568         bus_space_write_1(iot, ioh, EG_CONTROL, EG_CTL_CMDE);
  569 
  570         sc->eg_incount = 0;
  571         egrecv(sc);
  572 
  573         /* Interface is now `running', with no output active. */
  574         ifp->if_flags |= IFF_RUNNING;
  575         ifp->if_flags &= ~IFF_OACTIVE;
  576 
  577         /* Attempt to start output, if any. */
  578         egstart(ifp);
  579 }
  580 
  581 void
  582 egrecv(sc)
  583         struct eg_softc *sc;
  584 {
  585 
  586         while (sc->eg_incount < EG_INLEN) {
  587                 sc->eg_pcb[0] = EG_CMD_RECVPACKET;
  588                 sc->eg_pcb[1] = 0x08;
  589                 sc->eg_pcb[2] = 0; /* address not used.. we send zero */
  590                 sc->eg_pcb[3] = 0;
  591                 sc->eg_pcb[4] = 0;
  592                 sc->eg_pcb[5] = 0;
  593                 sc->eg_pcb[6] = EG_BUFLEN & 0xff; /* our buffer size */
  594                 sc->eg_pcb[7] = (EG_BUFLEN >> 8) & 0xff;
  595                 sc->eg_pcb[8] = 0; /* timeout, 0 == none */
  596                 sc->eg_pcb[9] = 0;
  597                 if (egwritePCB(sc->sc_iot, sc->sc_ioh, sc->eg_pcb) != 0)
  598                         break;
  599                 sc->eg_incount++;
  600         }
  601 }
  602 
  603 void
  604 egstart(ifp)
  605         struct ifnet *ifp;
  606 {
  607         struct eg_softc *sc = ifp->if_softc;
  608         bus_space_tag_t iot = sc->sc_iot;
  609         bus_space_handle_t ioh = sc->sc_ioh;
  610         struct mbuf *m0, *m;
  611         caddr_t buffer;
  612         int len;
  613         u_int16_t *ptr;
  614 
  615         /* Don't transmit if interface is busy or not running */
  616         if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING)
  617                 return;
  618 
  619 loop:
  620         /* Dequeue the next datagram. */
  621         IFQ_DEQUEUE(&ifp->if_snd, m0);
  622         if (m0 == 0)
  623                 return;
  624         
  625         ifp->if_flags |= IFF_OACTIVE;
  626 
  627         /* We need to use m->m_pkthdr.len, so require the header */
  628         if ((m0->m_flags & M_PKTHDR) == 0) {
  629                 printf("%s: no header mbuf\n", sc->sc_dev.dv_xname);
  630                 panic("egstart");
  631         }
  632         len = max(m0->m_pkthdr.len, ETHER_MIN_LEN - ETHER_CRC_LEN);
  633 
  634 #if NBPFILTER > 0
  635         if (ifp->if_bpf)
  636                 bpf_mtap(ifp->if_bpf, m0);
  637 #endif
  638 
  639         sc->eg_pcb[0] = EG_CMD_SENDPACKET;
  640         sc->eg_pcb[1] = 0x06;
  641         sc->eg_pcb[2] = 0; /* address not used, we send zero */
  642         sc->eg_pcb[3] = 0;
  643         sc->eg_pcb[4] = 0;
  644         sc->eg_pcb[5] = 0;
  645         sc->eg_pcb[6] = len; /* length of packet */
  646         sc->eg_pcb[7] = len >> 8;
  647         if (egwritePCB(iot, ioh, sc->eg_pcb) != 0) {
  648                 printf("%s: can't send Send Packet command\n",
  649                     sc->sc_dev.dv_xname);
  650                 ifp->if_oerrors++;
  651                 ifp->if_flags &= ~IFF_OACTIVE;
  652                 m_freem(m0);
  653                 goto loop;
  654         }
  655 
  656         buffer = sc->eg_outbuf;
  657         for (m = m0; m != 0; m = m->m_next) {
  658                 memcpy(buffer, mtod(m, caddr_t), m->m_len);
  659                 buffer += m->m_len;
  660         }
  661         if (len > m0->m_pkthdr.len)
  662                 memset(buffer, 0, len - m0->m_pkthdr.len);
  663 
  664         /* set direction bit: host -> adapter */
  665         bus_space_write_1(iot, ioh, EG_CONTROL,
  666             bus_space_read_1(iot, ioh, EG_CONTROL) & ~EG_CTL_DIR); 
  667         
  668         for (ptr = (u_int16_t *) sc->eg_outbuf; len > 0; len -= 2) {
  669                 bus_space_write_2(iot, ioh, EG_DATA, *ptr++);
  670                 while (!(bus_space_read_1(iot, ioh, EG_STATUS) & EG_STAT_HRDY))
  671                         ; /* XXX need timeout here */
  672         }
  673         
  674         m_freem(m0);
  675 }
  676 
  677 int
  678 egintr(arg)
  679         void *arg;
  680 {
  681         struct eg_softc *sc = arg;
  682         bus_space_tag_t iot = sc->sc_iot;
  683         bus_space_handle_t ioh = sc->sc_ioh;
  684         int i, len, serviced;
  685         u_int16_t *ptr;
  686 
  687         serviced = 0;
  688 
  689         while (bus_space_read_1(iot, ioh, EG_STATUS) & EG_STAT_ACRF) {
  690                 egreadPCB(iot, ioh, sc->eg_pcb);
  691                 switch (sc->eg_pcb[0]) {
  692                 case EG_RSP_RECVPACKET:
  693                         len = sc->eg_pcb[6] | (sc->eg_pcb[7] << 8);
  694         
  695                         /* Set direction bit : Adapter -> host */
  696                         bus_space_write_1(iot, ioh, EG_CONTROL,
  697                             bus_space_read_1(iot, ioh, EG_CONTROL) | EG_CTL_DIR); 
  698 
  699                         for (ptr = (u_int16_t *) sc->eg_inbuf;
  700                             len > 0; len -= 2) {
  701                                 while (!(bus_space_read_1(iot, ioh, EG_STATUS) &
  702                                     EG_STAT_HRDY))
  703                                         ;
  704                                 *ptr++ = bus_space_read_2(iot, ioh, EG_DATA);
  705                         }
  706 
  707                         len = sc->eg_pcb[8] | (sc->eg_pcb[9] << 8);
  708                         egread(sc, sc->eg_inbuf, len);
  709 
  710                         sc->eg_incount--;
  711                         egrecv(sc);
  712                         serviced = 1;
  713                         break;
  714 
  715                 case EG_RSP_SENDPACKET:
  716                         if (sc->eg_pcb[6] || sc->eg_pcb[7]) {
  717                                 DPRINTF(("%s: packet dropped\n",
  718                                     sc->sc_dev.dv_xname));
  719                                 sc->sc_ethercom.ec_if.if_oerrors++;
  720                         } else
  721                                 sc->sc_ethercom.ec_if.if_opackets++;
  722                         sc->sc_ethercom.ec_if.if_collisions +=
  723                             sc->eg_pcb[8] & 0xf;
  724                         sc->sc_ethercom.ec_if.if_flags &= ~IFF_OACTIVE;
  725                         egstart(&sc->sc_ethercom.ec_if);
  726                         serviced = 1;
  727                         break;
  728 
  729                 /* XXX byte-order and type-size bugs here... */
  730                 case EG_RSP_GETSTATS:
  731                         DPRINTF(("%s: Card Statistics\n",
  732                             sc->sc_dev.dv_xname));
  733                         memcpy(&i, &sc->eg_pcb[2], sizeof(i));
  734                         DPRINTF(("Receive Packets %d\n", i));
  735                         memcpy(&i, &sc->eg_pcb[6], sizeof(i));
  736                         DPRINTF(("Transmit Packets %d\n", i));
  737                         DPRINTF(("CRC errors %d\n",
  738                             *(short *) &sc->eg_pcb[10]));
  739                         DPRINTF(("alignment errors %d\n",
  740                             *(short *) &sc->eg_pcb[12]));
  741                         DPRINTF(("no resources errors %d\n",
  742                             *(short *) &sc->eg_pcb[14]));
  743                         DPRINTF(("overrun errors %d\n",
  744                             *(short *) &sc->eg_pcb[16]));
  745                         serviced = 1;
  746                         break;
  747                         
  748                 default:
  749                         printf("%s: egintr: Unknown response %x??\n",
  750                             sc->sc_dev.dv_xname, sc->eg_pcb[0]);
  751                         egprintpcb(sc->eg_pcb);
  752                         break;
  753                 }
  754 
  755 #if NRND > 0
  756                 rnd_add_uint32(&sc->rnd_source, sc->eg_pcb[0]);
  757 #endif
  758         }
  759 
  760         return serviced;
  761 }
  762 
  763 /*
  764  * Pass a packet up to the higher levels.
  765  */
  766 void
  767 egread(sc, buf, len)
  768         struct eg_softc *sc;
  769         caddr_t buf;
  770         int len;
  771 {
  772         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  773         struct mbuf *m;
  774         
  775         if (len <= sizeof(struct ether_header) ||
  776             len > ETHER_MAX_LEN) {
  777                 printf("%s: invalid packet size %d; dropping\n",
  778                     sc->sc_dev.dv_xname, len);
  779                 ifp->if_ierrors++;
  780                 return;
  781         }
  782 
  783         /* Pull packet off interface. */
  784         m = egget(sc, buf, len);
  785         if (m == 0) {
  786                 ifp->if_ierrors++;
  787                 return;
  788         }
  789 
  790         ifp->if_ipackets++;
  791 
  792 #if NBPFILTER > 0
  793         /*
  794          * Check if there's a BPF listener on this interface.
  795          * If so, hand off the raw packet to BPF.
  796          */
  797         if (ifp->if_bpf)
  798                 bpf_mtap(ifp->if_bpf, m);
  799 #endif
  800 
  801         (*ifp->if_input)(ifp, m);
  802 }
  803 
  804 /*
  805  * convert buf into mbufs
  806  */
  807 struct mbuf *
  808 egget(sc, buf, totlen)
  809         struct eg_softc *sc;
  810         caddr_t buf;
  811         int totlen;
  812 {
  813         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  814         struct mbuf *m, *m0, *newm;
  815         int len;
  816 
  817         MGETHDR(m0, M_DONTWAIT, MT_DATA);
  818         if (m0 == 0)
  819                 return (0);
  820         m0->m_pkthdr.rcvif = ifp;
  821         m0->m_pkthdr.len = totlen;
  822         len = MHLEN;
  823         m = m0;
  824 
  825         while (totlen > 0) {
  826                 if (totlen >= MINCLSIZE) {
  827                         MCLGET(m, M_DONTWAIT);
  828                         if ((m->m_flags & M_EXT) == 0)
  829                                 goto bad;
  830                         len = MCLBYTES;
  831                 }
  832 
  833                 m->m_len = len = min(totlen, len);
  834                 memcpy(mtod(m, caddr_t), (caddr_t)buf, len);
  835                 buf += len;
  836 
  837                 totlen -= len;
  838                 if (totlen > 0) {
  839                         MGET(newm, M_DONTWAIT, MT_DATA);
  840                         if (newm == 0)
  841                                 goto bad;
  842                         len = MLEN;
  843                         m = m->m_next = newm;
  844                 }
  845         }
  846 
  847         return (m0);
  848 
  849 bad:
  850         m_freem(m0);
  851         return (0);
  852 }
  853 
  854 int
  855 egioctl(ifp, cmd, data)
  856         struct ifnet *ifp;
  857         u_long cmd;
  858         caddr_t data;
  859 {
  860         struct eg_softc *sc = ifp->if_softc;
  861         struct ifaddr *ifa = (struct ifaddr *)data;
  862         int s, error = 0;
  863 
  864         s = splnet();
  865 
  866         switch (cmd) {
  867 
  868         case SIOCSIFADDR:
  869                 ifp->if_flags |= IFF_UP;
  870 
  871                 switch (ifa->ifa_addr->sa_family) {
  872 #ifdef INET
  873                 case AF_INET:
  874                         eginit(sc);
  875                         arp_ifinit(ifp, ifa);
  876                         break;
  877 #endif
  878 #ifdef NS
  879                 case AF_NS:
  880                     {
  881                         struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
  882                                 
  883                         if (ns_nullhost(*ina))
  884                                 ina->x_host =
  885                                    *(union ns_host *)LLADDR(ifp->if_sadl);
  886                         else
  887                                 memcpy(LLADDR(ifp->if_sadl), ina->x_host.c_host,
  888                                     ETHER_ADDR_LEN);
  889                         /* Set new address. */
  890                         eginit(sc);
  891                         break;
  892                     }
  893 #endif
  894                 default:
  895                         eginit(sc);
  896                         break;
  897                 }
  898                 break;
  899 
  900         case SIOCSIFFLAGS:
  901                 if ((ifp->if_flags & IFF_UP) == 0 &&
  902                     (ifp->if_flags & IFF_RUNNING) != 0) {
  903                         /*
  904                          * If interface is marked down and it is running, then
  905                          * stop it.
  906                          */
  907                         egstop(sc);
  908                         ifp->if_flags &= ~IFF_RUNNING;
  909                 } else if ((ifp->if_flags & IFF_UP) != 0 &&
  910                            (ifp->if_flags & IFF_RUNNING) == 0) {
  911                         /*
  912                          * If interface is marked up and it is stopped, then
  913                          * start it.
  914                          */
  915                         eginit(sc);
  916                 } else {
  917                         sc->eg_pcb[0] = EG_CMD_GETSTATS;
  918                         sc->eg_pcb[1] = 0;
  919                         if (egwritePCB(sc->sc_iot, sc->sc_ioh, sc->eg_pcb) != 0)
  920                                 DPRINTF(("write error\n"));
  921                         /*
  922                          * XXX deal with flags changes:
  923                          * IFF_MULTICAST, IFF_PROMISC,
  924                          * IFF_LINK0, IFF_LINK1,
  925                          */
  926                 }
  927                 break;
  928 
  929         default:
  930                 error = EINVAL;
  931                 break;
  932         }
  933 
  934         splx(s);
  935         return error;
  936 }
  937 
  938 void
  939 egreset(sc)
  940         struct eg_softc *sc;
  941 {
  942         int s;
  943 
  944         DPRINTF(("%s: egreset()\n", sc->sc_dev.dv_xname));
  945         s = splnet();
  946         egstop(sc);
  947         eginit(sc);
  948         splx(s);
  949 }
  950 
  951 void
  952 egwatchdog(ifp)
  953         struct ifnet *ifp;
  954 {
  955         struct eg_softc *sc = ifp->if_softc;
  956 
  957         log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
  958         sc->sc_ethercom.ec_if.if_oerrors++;
  959 
  960         egreset(sc);
  961 }
  962 
  963 void
  964 egstop(sc)
  965         struct eg_softc *sc;
  966 {
  967         
  968         bus_space_write_1(sc->sc_iot, sc->sc_ioh, EG_CONTROL, 0);
  969 }

Cache object: 24089fa87033abe48c59c900e22b008d


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