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 /*      $OpenBSD: if_eg.c,v 1.51 2022/04/06 18:59:28 naddy Exp $        */
    2 /*      $NetBSD: if_eg.c,v 1.26 1996/05/12 23:52:27 mycroft Exp $       */
    3 
    4 /*
    5  * Copyright (c) 1993 Dean Huxley <dean@fsa.ca>
    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  * 3. All advertising materials mentioning features or use of this software
   17  *    must display the following acknowledgement:
   18  *      This product includes software developed by Dean Huxley.
   19  * 4. The name of Dean Huxley may not be used to endorse or promote products
   20  *    derived from this software without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   32  */
   33 /*
   34  * Support for 3Com 3c505 Etherlink+ card.
   35  */
   36 
   37 /* To do:
   38  * - multicast
   39  * - promiscuous
   40  */
   41 #include "bpfilter.h"
   42 
   43 #include <sys/param.h>
   44 #include <sys/mbuf.h>
   45 #include <sys/socket.h>
   46 #include <sys/ioctl.h>
   47 #include <sys/errno.h>
   48 #include <sys/syslog.h>
   49 #include <sys/systm.h>
   50 #include <sys/selinfo.h>
   51 #include <sys/device.h>
   52 
   53 #include <net/if.h>
   54 
   55 #include <netinet/in.h>
   56 #include <netinet/if_ether.h>
   57 
   58 #if NBPFILTER > 0
   59 #include <net/bpf.h>
   60 #endif
   61 
   62 #include <machine/cpu.h>
   63 #include <machine/intr.h>
   64 
   65 #include <dev/isa/isavar.h>
   66 #include <dev/isa/if_egreg.h>
   67 #include <dev/isa/elink.h>
   68 
   69 /* for debugging convenience */
   70 #ifdef EGDEBUG
   71 #define DPRINTF(x) printf x
   72 #else
   73 #define DPRINTF(x)
   74 #endif
   75 
   76 #define EG_INLEN        10
   77 #define EG_BUFLEN       0x0670
   78 
   79 /*
   80  * Ethernet software status per interface.
   81  */
   82 struct eg_softc {
   83         struct device sc_dev;
   84         void *sc_ih;
   85         bus_space_tag_t sc_bst;
   86         bus_space_handle_t sc_bsh;
   87         struct arpcom sc_arpcom;        /* Ethernet common part */
   88         u_char  eg_rom_major;           /* Cards ROM version (major number) */ 
   89         u_char  eg_rom_minor;           /* Cards ROM version (minor number) */ 
   90         short   eg_ram;                 /* Amount of RAM on the card */
   91         u_char  eg_pcb[64];             /* Primary Command Block buffer */
   92         u_char  eg_incount;             /* Number of buffers currently used */
   93         u_char  *eg_inbuf;              /* Incoming packet buffer */
   94         u_char  *eg_outbuf;             /* Outgoing packet buffer */
   95 };
   96 
   97 int egprobe(struct device *, void *, void *);
   98 void egattach(struct device *, struct device *, void *);
   99 
  100 const struct cfattach eg_ca = {
  101         sizeof(struct eg_softc), egprobe, egattach
  102 };
  103 
  104 struct cfdriver eg_cd = {
  105         NULL, "eg", DV_IFNET
  106 };
  107 
  108 int egintr(void *);
  109 void eginit(struct eg_softc *);
  110 int egioctl(struct ifnet *, u_long, caddr_t);
  111 void egrecv(struct eg_softc *);
  112 void egstart(struct ifnet *);
  113 void egwatchdog(struct ifnet *);
  114 void egreset(struct eg_softc *);
  115 void egread(struct eg_softc *, caddr_t, int);
  116 struct mbuf *egget(struct eg_softc *, caddr_t, int);
  117 void egstop(struct eg_softc *);
  118 
  119 static __inline void egprintpcb(struct eg_softc *);
  120 static int egoutPCB(struct eg_softc *, u_char);
  121 static int egreadPCBstat(struct eg_softc *, u_char);
  122 static int egreadPCBready(struct eg_softc *);
  123 static int egwritePCB(struct eg_softc *);
  124 static int egreadPCB(struct eg_softc *);
  125 
  126 /*
  127  * Support stuff
  128  */
  129         
  130 static __inline void
  131 egprintpcb(struct eg_softc *sc)
  132 {
  133         int i;
  134         
  135         for (i = 0; i < sc->eg_pcb[1] + 2; i++)
  136                 DPRINTF(("pcb[%2d] = %x\n", i, sc->eg_pcb[i]));
  137 }
  138 
  139 
  140 static int
  141 egoutPCB(struct eg_softc *sc, u_char b)
  142 {
  143         bus_space_tag_t bst = sc->sc_bst;
  144         bus_space_handle_t bsh = sc->sc_bsh;
  145         int i;
  146 
  147         for (i = 0; i < 4000; i++) {
  148                 if (bus_space_read_1(bst, bsh, EG_STATUS) & EG_STAT_HCRE) {
  149                         bus_space_write_1(bst, bsh, EG_COMMAND, b);
  150                         return 0;
  151                 }
  152                 delay(10);
  153         }
  154         DPRINTF(("egoutPCB failed\n"));
  155         return (1);
  156 }
  157         
  158 static int
  159 egreadPCBstat(struct eg_softc *sc, u_char statb)
  160 {
  161         bus_space_tag_t bst = sc->sc_bst;
  162         bus_space_handle_t bsh = sc->sc_bsh;
  163         int i;
  164 
  165         for (i=0; i < 5000; i++) {
  166                 if ((bus_space_read_1(bst, bsh, EG_STATUS) & EG_PCB_STAT) !=
  167                     EG_PCB_NULL) 
  168                         break;
  169                 delay(10);
  170         }
  171         if ((bus_space_read_1(bst, bsh, EG_STATUS) & EG_PCB_STAT) == statb) 
  172                 return (0);
  173         return (1);
  174 }
  175 
  176 static int
  177 egreadPCBready(struct eg_softc *sc)
  178 {
  179         bus_space_tag_t bst = sc->sc_bst;
  180         bus_space_handle_t bsh = sc->sc_bsh;
  181         int i;
  182 
  183         for (i=0; i < 10000; i++) {
  184                 if (bus_space_read_1(bst, bsh, EG_STATUS) & EG_STAT_ACRF)
  185                         return (0);
  186                 delay(5);
  187         }
  188         DPRINTF(("PCB read not ready status %02x\n",
  189             bus_space_read_1(bst, bsh, EG_STATUS)));
  190         return (1);
  191 }
  192         
  193 static int
  194 egwritePCB(struct eg_softc *sc)
  195 {
  196         bus_space_tag_t bst = sc->sc_bst;
  197         bus_space_handle_t bsh = sc->sc_bsh;
  198         int i;
  199         u_char len;
  200 
  201         bus_space_write_1(bst, bsh, EG_CONTROL,
  202             (bus_space_read_1(bst, bsh, EG_CONTROL) & ~EG_PCB_STAT) |
  203             EG_PCB_NULL);
  204 
  205         len = sc->eg_pcb[1] + 2;
  206         for (i = 0; i < len; i++)
  207                 egoutPCB(sc, sc->eg_pcb[i]);
  208         
  209         for (i=0; i < 4000; i++) {
  210                 if (bus_space_read_1(bst, bsh, EG_STATUS) & EG_STAT_HCRE)
  211                         break;
  212                 delay(10);
  213         }
  214 
  215         bus_space_write_1(bst, bsh, EG_CONTROL,
  216             (bus_space_read_1(bst, bsh, EG_CONTROL) & ~EG_PCB_STAT) |
  217             EG_PCB_DONE);
  218 
  219         egoutPCB(sc, len);
  220 
  221         if (egreadPCBstat(sc, EG_PCB_ACCEPT))
  222                 return (1);
  223         return (0);
  224 }       
  225         
  226 static int
  227 egreadPCB(struct eg_softc *sc)
  228 {
  229         bus_space_tag_t bst = sc->sc_bst;
  230         bus_space_handle_t bsh = sc->sc_bsh;
  231         int i;
  232         u_char b;
  233         
  234         bus_space_write_1(bst, bsh, EG_CONTROL,
  235             (bus_space_read_1(bst, bsh, EG_CONTROL) & ~EG_PCB_STAT) |
  236             EG_PCB_NULL);
  237 
  238         bzero(sc->eg_pcb, sizeof(sc->eg_pcb));
  239 
  240         if (egreadPCBready(sc))
  241                 return (1);
  242 
  243         sc->eg_pcb[0] = bus_space_read_1(bst, bsh, EG_COMMAND);
  244         
  245         if (egreadPCBready(sc))
  246                 return (1);
  247 
  248         sc->eg_pcb[1] = bus_space_read_1(bst, bsh, EG_COMMAND);
  249 
  250         if (sc->eg_pcb[1] > 62) {
  251                 DPRINTF(("len %d too large\n", sc->eg_pcb[1]));
  252                 return (1);
  253         }
  254         
  255         for (i = 0; i < sc->eg_pcb[1]; i++) {
  256                 if (egreadPCBready(sc))
  257                         return (1);
  258                 sc->eg_pcb[2+i] = bus_space_read_1(bst, bsh, EG_COMMAND);
  259         }
  260         if (egreadPCBready(sc))
  261                 return (1);
  262         if (egreadPCBstat(sc, EG_PCB_DONE))
  263                 return (1);
  264         if ((b = bus_space_read_1(bst, bsh, EG_COMMAND)) != sc->eg_pcb[1] + 2) {
  265                 DPRINTF(("%d != %d\n", b, sc->eg_pcb[1] + 2));
  266                 return (1);
  267         }
  268 
  269         bus_space_write_1(bst, bsh, EG_CONTROL,
  270             (bus_space_read_1(bst, bsh, EG_CONTROL) & ~EG_PCB_STAT) |
  271             EG_PCB_ACCEPT);
  272 
  273         return (0);
  274 }       
  275 
  276 /*
  277  * Real stuff
  278  */
  279 
  280 int
  281 egprobe(struct device *parent, void *match, void *aux)
  282 {
  283         struct eg_softc *sc = match;
  284         struct isa_attach_args *ia = aux;
  285         bus_space_tag_t bst = sc->sc_bst = ia->ia_iot;
  286         bus_space_handle_t bsh;
  287         int i;
  288 
  289         if ((ia->ia_iobase & ~0x07f0) != 0) {
  290                 DPRINTF(("Weird iobase %x\n", ia->ia_iobase));
  291                 return (0);
  292         }
  293         
  294         if (bus_space_map(bst, ia->ia_iobase, EG_IO_PORTS, 0, &bsh)) {
  295                 DPRINTF(("%s: can't map i/o space\n", sc->sc_dev.dv_xname));
  296                 return (0);
  297         }
  298         sc->sc_bsh = bsh;
  299 
  300         /* hard reset card */
  301         bus_space_write_1(bst, bsh, EG_CONTROL, EG_CTL_RESET); 
  302         bus_space_write_1(bst, bsh, EG_CONTROL, 0);
  303         for (i = 0; i < 5000; i++) {
  304                 delay(1000);
  305                 if ((bus_space_read_1(bst, bsh, EG_STATUS) & EG_PCB_STAT) ==
  306                     EG_PCB_NULL) 
  307                         break;
  308         }
  309         if ((bus_space_read_1(bst, bsh, EG_STATUS) & EG_PCB_STAT) !=
  310             EG_PCB_NULL) {
  311                 DPRINTF(("eg: Reset failed\n"));
  312                 goto lose;
  313         }
  314         sc->eg_pcb[0] = EG_CMD_GETINFO; /* Get Adapter Info */
  315         sc->eg_pcb[1] = 0;
  316         if (egwritePCB(sc) != 0)
  317                 goto lose;
  318         
  319         if (egreadPCB(sc) != 0) {
  320                 egprintpcb(sc);
  321                 goto lose;
  322         }
  323 
  324         if (sc->eg_pcb[0] != EG_RSP_GETINFO || /* Get Adapter Info Response */
  325             sc->eg_pcb[1] != 0x0a) {
  326                 egprintpcb(sc);
  327                 goto lose;
  328         }
  329         sc->eg_rom_major = sc->eg_pcb[3];
  330         sc->eg_rom_minor = sc->eg_pcb[2];
  331         sc->eg_ram = sc->eg_pcb[6] | (sc->eg_pcb[7] << 8);
  332         
  333         ia->ia_iosize = 0x08;
  334         ia->ia_msize = 0;
  335         bus_space_unmap(bst, bsh, EG_IO_PORTS);
  336         return (1);
  337 
  338 lose:
  339         bus_space_unmap(bst, bsh, EG_IO_PORTS);
  340         return (0);
  341 }
  342 
  343 void
  344 egattach(struct device *parent, struct device *self, void *aux)
  345 {
  346         struct eg_softc *sc = (void *)self;
  347         struct isa_attach_args *ia = aux;
  348         bus_space_tag_t bst = sc->sc_bst = ia->ia_iot;
  349         bus_space_handle_t bsh;
  350         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
  351         
  352         if (bus_space_map(bst, ia->ia_iobase, EG_IO_PORTS, 0, &bsh)) {
  353                 printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname);
  354                 return;
  355         }
  356         sc->sc_bsh = bsh;
  357 
  358         egstop(sc);
  359 
  360         sc->eg_pcb[0] = EG_CMD_GETEADDR; /* Get Station address */
  361         sc->eg_pcb[1] = 0;
  362         if (egwritePCB(sc) != 0) {
  363                 DPRINTF(("write error\n"));
  364                 return;
  365         }       
  366         if (egreadPCB(sc) != 0) {
  367                 DPRINTF(("read error\n"));
  368                 egprintpcb(sc);
  369                 return;
  370         }
  371 
  372         /* check Get station address response */
  373         if (sc->eg_pcb[0] != EG_RSP_GETEADDR || sc->eg_pcb[1] != 0x06) { 
  374                 DPRINTF(("parse error\n"));
  375                 egprintpcb(sc);
  376                 return;
  377         }
  378         bcopy(&sc->eg_pcb[2], sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
  379 
  380         printf(": ROM v%d.%02d %dk address %s\n",
  381             sc->eg_rom_major, sc->eg_rom_minor, sc->eg_ram,
  382             ether_sprintf(sc->sc_arpcom.ac_enaddr));
  383 
  384         sc->eg_pcb[0] = EG_CMD_SETEADDR; /* Set station address */
  385         if (egwritePCB(sc) != 0) {
  386                 DPRINTF(("write error2\n"));
  387                 return;
  388         }
  389         if (egreadPCB(sc) != 0) {
  390                 DPRINTF(("read error2\n"));
  391                 egprintpcb(sc);
  392                 return;
  393         }
  394         if (sc->eg_pcb[0] != EG_RSP_SETEADDR || sc->eg_pcb[1] != 0x02 ||
  395             sc->eg_pcb[2] != 0 || sc->eg_pcb[3] != 0) {
  396                 DPRINTF(("parse error2\n"));
  397                 egprintpcb(sc);
  398                 return;
  399         }
  400 
  401         /* Initialize ifnet structure. */
  402         bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
  403         ifp->if_softc = sc;
  404         ifp->if_start = egstart;
  405         ifp->if_ioctl = egioctl;
  406         ifp->if_watchdog = egwatchdog;
  407         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
  408         
  409         /* Now we can attach the interface. */
  410         if_attach(ifp);
  411         ether_ifattach(ifp);
  412         
  413         sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
  414             IPL_NET, egintr, sc, sc->sc_dev.dv_xname);
  415 }
  416 
  417 void
  418 eginit(register struct eg_softc *sc)
  419 {
  420         bus_space_tag_t bst = sc->sc_bst;
  421         bus_space_handle_t bsh = sc->sc_bsh;
  422         register struct ifnet *ifp = &sc->sc_arpcom.ac_if;
  423 
  424         /* soft reset the board */
  425         bus_space_write_1(bst, bsh, EG_CONTROL, EG_CTL_FLSH);
  426         delay(100);
  427         bus_space_write_1(bst, bsh, EG_CONTROL, EG_CTL_ATTN);
  428         delay(100);
  429         bus_space_write_1(bst, bsh, EG_CONTROL, 0);
  430         delay(200);
  431 
  432         sc->eg_pcb[0] = EG_CMD_CONFIG82586; /* Configure 82586 */
  433         sc->eg_pcb[1] = 2;
  434         sc->eg_pcb[2] = 3; /* receive broadcast & multicast */
  435         sc->eg_pcb[3] = 0;
  436         if (egwritePCB(sc) != 0)
  437                 DPRINTF(("write error3\n"));
  438 
  439         if (egreadPCB(sc) != 0) {
  440                 DPRINTF(("read error3\n"));
  441                 egprintpcb(sc);
  442         } else if (sc->eg_pcb[2] != 0 || sc->eg_pcb[3] != 0)
  443                 printf("%s: configure card command failed\n",
  444                     sc->sc_dev.dv_xname);
  445 
  446         if (sc->eg_inbuf == 0)
  447                 sc->eg_inbuf = malloc(EG_BUFLEN, M_TEMP, M_NOWAIT);
  448         sc->eg_incount = 0;
  449 
  450         if (sc->eg_outbuf == 0)
  451                 sc->eg_outbuf = malloc(EG_BUFLEN, M_TEMP, M_NOWAIT);
  452 
  453         bus_space_write_1(bst, bsh, EG_CONTROL, EG_CTL_CMDE);
  454 
  455         sc->eg_incount = 0;
  456         egrecv(sc);
  457 
  458         /* Interface is now `running', with no output active. */
  459         ifp->if_flags |= IFF_RUNNING;
  460         ifq_clr_oactive(&ifp->if_snd);
  461 
  462         /* Attempt to start output, if any. */
  463         egstart(ifp);
  464 }
  465 
  466 void
  467 egrecv(struct eg_softc *sc)
  468 {
  469         while (sc->eg_incount < EG_INLEN) {
  470                 sc->eg_pcb[0] = EG_CMD_RECVPACKET;
  471                 sc->eg_pcb[1] = 0x08;
  472                 sc->eg_pcb[2] = 0; /* address not used.. we send zero */
  473                 sc->eg_pcb[3] = 0;
  474                 sc->eg_pcb[4] = 0;
  475                 sc->eg_pcb[5] = 0;
  476                 sc->eg_pcb[6] = EG_BUFLEN & 0xff; /* our buffer size */
  477                 sc->eg_pcb[7] = (EG_BUFLEN >> 8) & 0xff;
  478                 sc->eg_pcb[8] = 0; /* timeout, 0 == none */
  479                 sc->eg_pcb[9] = 0;
  480                 if (egwritePCB(sc) != 0)
  481                         break;
  482                 sc->eg_incount++;
  483         }
  484 }
  485 
  486 void
  487 egstart(struct ifnet *ifp)
  488 {
  489         struct eg_softc *sc = ifp->if_softc;
  490         bus_space_tag_t bst = sc->sc_bst;
  491         bus_space_handle_t bsh = sc->sc_bsh;
  492         struct mbuf *m0, *m;
  493         caddr_t buffer;
  494         int len;
  495         u_short *ptr;
  496         u_int i;
  497 
  498         /* Don't transmit if interface is busy or not running */
  499         if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd))
  500                 return;
  501 
  502 loop:
  503         /* Dequeue the next datagram. */
  504         m0 = ifq_dequeue(&ifp->if_snd);
  505         if (m0 == NULL)
  506                 return;
  507         
  508         ifq_set_oactive(&ifp->if_snd);
  509 
  510         /* We need to use m->m_pkthdr.len, so require the header */
  511         if ((m0->m_flags & M_PKTHDR) == 0)
  512                 panic("egstart: no header mbuf");
  513         len = max(m0->m_pkthdr.len, ETHER_MIN_LEN);
  514 
  515 #if NBPFILTER > 0
  516         if (ifp->if_bpf)
  517                 bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
  518 #endif
  519 
  520         sc->eg_pcb[0] = EG_CMD_SENDPACKET;
  521         sc->eg_pcb[1] = 0x06;
  522         sc->eg_pcb[2] = 0; /* address not used, we send zero */
  523         sc->eg_pcb[3] = 0;
  524         sc->eg_pcb[4] = 0;
  525         sc->eg_pcb[5] = 0;
  526         sc->eg_pcb[6] = len; /* length of packet */
  527         sc->eg_pcb[7] = len >> 8;
  528         if (egwritePCB(sc) != 0) {
  529                 DPRINTF(("egwritePCB in egstart failed\n"));
  530                 ifp->if_oerrors++;
  531                 ifq_clr_oactive(&ifp->if_snd);
  532                 m_freem(m0);
  533                 goto loop;
  534         }
  535 
  536         buffer = sc->eg_outbuf;
  537         for (m = m0; m != 0; m = m->m_next) {
  538                 bcopy(mtod(m, caddr_t), buffer, m->m_len);
  539                 buffer += m->m_len;
  540         }
  541         if (len > m0->m_pkthdr.len)
  542                 bzero(buffer, len - m0->m_pkthdr.len);
  543 
  544         /* set direction bit: host -> adapter */
  545         bus_space_write_1(bst, bsh, EG_CONTROL,
  546             bus_space_read_1(bst, bsh, EG_CONTROL) & ~EG_CTL_DIR); 
  547         
  548         for (ptr = (u_short *)sc->eg_outbuf; len > 0; len -= 2) {
  549                 bus_space_write_2(bst, bsh, EG_DATA, *ptr++);
  550                 for (i = 10000; i != 0; i--) {
  551                         if (bus_space_read_1(bst, bsh, EG_STATUS) & EG_STAT_HRDY)
  552                                 break;
  553                         delay(10);
  554                 }
  555                 if (i == 0) {
  556                         printf("%s: start failed\n", sc->sc_dev.dv_xname);
  557                         break;
  558                 }
  559         }
  560         
  561         m_freem(m0);
  562 }
  563 
  564 int
  565 egintr(void *arg)
  566 {
  567         struct eg_softc *sc = arg;
  568         bus_space_tag_t bst = sc->sc_bst;
  569         bus_space_handle_t bsh = sc->sc_bsh;
  570         int ret = 0;
  571         int i, len;
  572         u_short *ptr;
  573 
  574         while (bus_space_read_1(bst, bsh, EG_STATUS) & EG_STAT_ACRF) {
  575                 ret = 1;
  576                 egreadPCB(sc);
  577                 switch (sc->eg_pcb[0]) {
  578                 case EG_RSP_RECVPACKET:
  579                         len = sc->eg_pcb[6] | (sc->eg_pcb[7] << 8);
  580         
  581                         /* Set direction bit : Adapter -> host */
  582                         bus_space_write_1(bst, bsh, EG_CONTROL,
  583                             bus_space_read_1(bst, bsh, EG_CONTROL) |
  584                             EG_CTL_DIR); 
  585 
  586                         for (ptr = (u_short *)sc->eg_inbuf; len > 0; len -= 2) {
  587                                 for (i = 10000; i != 0; i--) {
  588                                         if (bus_space_read_1(bst, bsh, EG_STATUS) & EG_STAT_HRDY)
  589                                                 break;
  590                                         delay(10);
  591                                 }
  592                                 if (i == 0) {
  593                                         printf("%s: receive failed\n",
  594                                             sc->sc_dev.dv_xname);
  595                                         break;
  596                                 }
  597                                 *ptr++ = bus_space_read_2(bst, bsh, EG_DATA);
  598                         }
  599 
  600                         if (len <= 0) {
  601                                 len = sc->eg_pcb[8] | (sc->eg_pcb[9] << 8);
  602                                 egread(sc, sc->eg_inbuf, len);
  603 
  604                                 sc->eg_incount--;
  605                                 egrecv(sc);
  606                         }
  607                         break;
  608 
  609                 case EG_RSP_SENDPACKET:
  610                         if (sc->eg_pcb[6] || sc->eg_pcb[7]) {
  611                                 DPRINTF(("packet dropped\n"));
  612                                 sc->sc_arpcom.ac_if.if_oerrors++;
  613                         }
  614                         sc->sc_arpcom.ac_if.if_collisions +=
  615                             sc->eg_pcb[8] & 0xf;
  616                         ifq_clr_oactive(&sc->sc_arpcom.ac_if.if_snd);
  617                         egstart(&sc->sc_arpcom.ac_if);
  618                         break;
  619 
  620                 case EG_RSP_GETSTATS:
  621                         DPRINTF(("Card Statistics\n"));
  622                         bcopy(&sc->eg_pcb[2], &i, sizeof(i));
  623                         DPRINTF(("Receive Packets %d\n", i));
  624                         bcopy(&sc->eg_pcb[6], &i, sizeof(i));
  625                         DPRINTF(("Transmit Packets %d\n", i));
  626                         DPRINTF(("CRC errors %d\n", *(short *)&sc->eg_pcb[10]));
  627                         DPRINTF(("alignment errors %d\n",
  628                             *(short *)&sc->eg_pcb[12]));
  629                         DPRINTF(("no resources errors %d\n",
  630                             *(short *)&sc->eg_pcb[14]));
  631                         DPRINTF(("overrun errors %d\n",
  632                             *(short *)&sc->eg_pcb[16]));
  633                         break;
  634                         
  635                 default:
  636                         DPRINTF(("egintr: Unknown response %x??\n",
  637                             sc->eg_pcb[0]));
  638                         egprintpcb(sc);
  639                         break;
  640                 }
  641         }
  642 
  643         return (ret);
  644 }
  645 
  646 /*
  647  * Pass a packet up to the higher levels.
  648  */
  649 void
  650 egread(struct eg_softc *sc, caddr_t buf, int len)
  651 {
  652         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
  653         struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  654         struct mbuf *m;
  655 
  656         if (len <= sizeof(struct ether_header) ||
  657             len > ETHER_MAX_LEN) {
  658                 printf("%s: invalid packet size %d; dropping\n",
  659                     sc->sc_dev.dv_xname, len);
  660                 ifp->if_ierrors++;
  661                 return;
  662         }
  663 
  664         /* Pull packet off interface. */
  665         m = egget(sc, buf, len);
  666         if (m == NULL) {
  667                 ifp->if_ierrors++;
  668                 return;
  669         }
  670 
  671         ml_enqueue(&ml, m);
  672         if_input(ifp, &ml);
  673 }
  674 
  675 /*
  676  * convert buf into mbufs
  677  */
  678 struct mbuf *
  679 egget(struct eg_softc *sc, caddr_t buf, int totlen)
  680 {
  681         struct mbuf *top, **mp, *m;
  682         int len;
  683 
  684         MGETHDR(m, M_DONTWAIT, MT_DATA);
  685         if (m == NULL)
  686                 return (0);
  687         m->m_pkthdr.len = totlen;
  688         len = MHLEN;
  689         top = 0;
  690         mp = &top;
  691 
  692         while (totlen > 0) {
  693                 if (top) {
  694                         MGET(m, M_DONTWAIT, MT_DATA);
  695                         if (m == NULL) {
  696                                 m_freem(top);
  697                                 return (0);
  698                         }
  699                         len = MLEN;
  700                 }
  701                 if (totlen >= MINCLSIZE) {
  702                         MCLGET(m, M_DONTWAIT);
  703                         if (m->m_flags & M_EXT)
  704                                 len = MCLBYTES;
  705                 }
  706                 m->m_len = len = min(totlen, len);
  707                 bcopy((caddr_t)buf, mtod(m, caddr_t), len);
  708                 buf += len;
  709                 totlen -= len;
  710                 *mp = m;
  711                 mp = &m->m_next;
  712         }
  713 
  714         return (top);
  715 }
  716 
  717 int
  718 egioctl(register struct ifnet *ifp, u_long cmd, caddr_t data)
  719 {
  720         struct eg_softc *sc = ifp->if_softc;
  721         int s, error = 0;
  722 
  723         s = splnet();
  724 
  725         switch (cmd) {
  726         case SIOCSIFADDR:
  727                 ifp->if_flags |= IFF_UP;
  728                 eginit(sc);
  729                 break;
  730 
  731         case SIOCSIFFLAGS:
  732                 if ((ifp->if_flags & IFF_UP) == 0 &&
  733                     (ifp->if_flags & IFF_RUNNING) != 0) {
  734                         /*
  735                          * If interface is marked down and it is running, then
  736                          * stop it.
  737                          */
  738                         egstop(sc);
  739                         ifp->if_flags &= ~IFF_RUNNING;
  740                 } else if ((ifp->if_flags & IFF_UP) != 0 &&
  741                            (ifp->if_flags & IFF_RUNNING) == 0) {
  742                         /*
  743                          * If interface is marked up and it is stopped, then
  744                          * start it.
  745                          */
  746                         eginit(sc);
  747                 } else {
  748                         sc->eg_pcb[0] = EG_CMD_GETSTATS;
  749                         sc->eg_pcb[1] = 0;
  750                         if (egwritePCB(sc) != 0)
  751                                 DPRINTF(("write error\n"));
  752                         /*
  753                          * XXX deal with flags changes:
  754                          * IFF_MULTICAST, IFF_PROMISC,
  755                          * IFF_LINK0, IFF_LINK1,
  756                          */
  757                 }
  758                 break;
  759 
  760         default:
  761                 error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data);
  762         }
  763 
  764         splx(s);
  765         return (error);
  766 }
  767 
  768 void
  769 egreset(struct eg_softc *sc)
  770 {
  771         int s;
  772 
  773         DPRINTF(("egreset()\n"));
  774         s = splnet();
  775         egstop(sc);
  776         eginit(sc);
  777         splx(s);
  778 }
  779 
  780 void
  781 egwatchdog(struct ifnet *ifp)
  782 {
  783         struct eg_softc *sc = ifp->if_softc;
  784 
  785         log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
  786         sc->sc_arpcom.ac_if.if_oerrors++;
  787 
  788         egreset(sc);
  789 }
  790 
  791 void
  792 egstop(register struct eg_softc *sc)
  793 {
  794         bus_space_tag_t bst = sc->sc_bst;
  795         bus_space_handle_t bsh = sc->sc_bsh;
  796         
  797         bus_space_write_1(bst, bsh, EG_CONTROL, 0);
  798 }

Cache object: 3b2b3b08071a876216b1863511b63b2b


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