*BSD News Article 55481


Return to BSD News archive

Path: euryale.cc.adfa.oz.au!newshost.anu.edu.au!harbinger.cc.monash.edu.au!simtel!pravda.aa.msen.com!news1.best.com!shellx.best.com!hokianga.live.com!user
From: finlayson@live.com (Ross Finlayson)
Newsgroups: comp.unix.bsd.freebsd.misc
Subject: Re: Multicast support in the 3COM 3C509B (ep0) driver?
Date: Mon, 20 Nov 1995 01:51:29 -0800
Organization: Live Networks, Inc.
Lines: 605
Distribution: world
Message-ID: <finlayson-2011950151290001@hokianga.live.com>
References: <finlayson-1811950121040001@hokianga.live.com> <48mp5g$4eh@phantom.min.ntt.jp>
NNTP-Posting-Host: hokianga.live.com

In article <48mp5g$4eh@phantom.min.ntt.jp>, ishizuka@isis.min.ntt.jp
(Masachika ISHIZUKA) wrote:

>   I don't know why the 3c509b driver with 2.1.0-XXX does not
> support multicast addressing, but patches for 3c509 driver
> can be found by using http://www.freebsd.com/search.html.

Thanks for the tip.  I was able to find the following patch (by Serge
Babkin@hq.icb.chel.su) in the mail archive.  (I'm repeating it below, in
case it didn't make it into the 2.1.0 release.)

   Ross.

=============== CUT HERE =============================
*** if_ep.c Mon Oct 23 08:25:55 1995
--- /sys/i386/isa/if_ep.c  Wed Oct 18 12:30:37 1995
***************
*** 87,92 ****
--- 85,95 ----
  #include <netns/ns_if.h>
  #endif
  
+ #ifdef IPX
+ #include <netipx/ipx.h>
+ #include <netipx/ipx_if.h>
+ #endif
+ 
  #if NBPFILTER > 0
  #include <net/bpf.h>
  #include <net/bpfdesc.h>
***************
*** 100,105 ****
--- 103,109 ----
  #include <i386/isa/isa_device.h>
  #include <i386/isa/icu.h>
  #include <i386/isa/if_epreg.h>
+ #include <i386/isa/elink.h>
  
  static int epprobe __P((struct isa_device *));
  static int epattach __P((struct isa_device *));
***************
*** 117,122 ****
--- 121,127 ----
  
  static int send_ID_sequence __P((int));
  static int get_eeprom_data __P((int, int));
+ static struct ep_board *ep_look_for_board_at(struct isa_device *);
  
  struct ep_softc ep_softc[NEP];
  
***************
*** 132,145 ****
  };
  
  static struct kern_devconf kdc_ep[NEP] = { {
!       0, 0, 0,        /* filled in by dev_attach */
        "ep", 0, { MDDT_ISA, 0, "net" },
        isa_generic_externalize, 0, 0, ISA_EXTERNALLEN,
!       &kdc_isa0,      /* parent */
!       0,        /* parentdata */
!       DC_UNCONFIGURED,      /* state */
        "3Com 3C509 Ethernet adapter",
!       DC_CLS_NETIF    /* class */
  } };
  
  static inline void
--- 137,150 ----
  };
  
  static struct kern_devconf kdc_ep[NEP] = { {
!       0, 0, 0,                /* filled in by dev_attach */
        "ep", 0, { MDDT_ISA, 0, "net" },
        isa_generic_externalize, 0, 0, ISA_EXTERNALLEN,
!       &kdc_isa0,              /* parent */
!       0,                      /* parentdata */
!       DC_UNCONFIGURED,        /* state */
        "3Com 3C509 Ethernet adapter",
!       DC_CLS_NETIF            /* class */
  } };
  
  static inline void
***************
*** 154,164 ****
  
  int ep_current_tag = EP_LAST_TAG + 1;
  
! struct {
!  int epb_addr;  /* address of this board */
!  char epb_used; /* was this entry already used for configuring ? */
!  }
!  ep_board[EP_MAX_BOARDS + 1];
  
  static int
  eeprom_rdy(is)
--- 159,165 ----
  
  int ep_current_tag = EP_LAST_TAG + 1;
  
! struct ep_board ep_board[EP_MAX_BOARDS + 1];
  
  static int
  eeprom_rdy(is)
***************
*** 174,184 ****
      return (1);
  }
  
! static int
  ep_look_for_board_at(is)
      struct isa_device *is;
  {
!     int data, i, j, io_base, id_port = EP_ID_PORT;
      int nisa = 0, neisa = 0;
  
      if (ep_current_tag == (EP_LAST_TAG + 1)) {
--- 175,185 ----
      return (1);
  }
  
! static struct ep_board *
  ep_look_for_board_at(is)
      struct isa_device *is;
  {
!     int data, i, j, io_base, id_port = ELINK_ID_PORT;
      int nisa = 0, neisa = 0;
  
      if (ep_current_tag == (EP_LAST_TAG + 1)) {
***************
*** 203,232 ****
        * Once activated, all the registers are mapped in the range
        * x000 - x00F, where x is the slot number.
               */
       ep_board[neisa].epb_used = 0;
       ep_board[neisa++].epb_addr = j * EP_EISA_START;
   }
   ep_current_tag--;
  
          /* Look for the ISA boards. Init and leave them actived */
   outb(id_port, 0xc0); /* Global reset */
   DELAY(10000);
   for (i = 0; i < EP_MAX_BOARDS; i++) {
       outb(id_port, 0);
       outb(id_port, 0);
       send_ID_sequence(id_port);
  
       data = get_eeprom_data(id_port, EEPROM_MFG_ID);
       if (data != MFG_ID)
      break;
  
       /* resolve contention using the Ethernet address */
       for (j = 0; j < 3; j++)
!     data = get_eeprom_data(id_port, j);
  
       ep_board[neisa+nisa].epb_used = 0;
       ep_board[neisa+nisa++].epb_addr =
!     (get_eeprom_data(id_port, EEPROM_ADDR_CFG) & 0x1f) * 0x10 + 0x200;
       outb(id_port, ep_current_tag);  /* tags board */
       outb(id_port, ACTIVATE_ADAPTER_TO_CONFIG);
       ep_current_tag--;
--- 204,265 ----
        * Once activated, all the registers are mapped in the range
        * x000 - x00F, where x is the slot number.
               */
+      ep_board[neisa].epb_isa = 0;
       ep_board[neisa].epb_used = 0;
       ep_board[neisa++].epb_addr = j * EP_EISA_START;
   }
   ep_current_tag--;
  
          /* Look for the ISA boards. Init and leave them actived */
+  outb(id_port, 0);
+  outb(id_port, 0);
+ 
+ #if 0
+  send_ID_sequence(id_port);
+ #else
+  elink_idseq(0xCF);
+ #endif
+ 
+ #if 0
   outb(id_port, 0xc0); /* Global reset */
+ #else
+  elink_reset();
+ #endif
   DELAY(10000);
   for (i = 0; i < EP_MAX_BOARDS; i++) {
       outb(id_port, 0);
       outb(id_port, 0);
+ #if 0
       send_ID_sequence(id_port);
+ #else
+      elink_idseq(0xCF);
+ #endif
  
       data = get_eeprom_data(id_port, EEPROM_MFG_ID);
       if (data != MFG_ID)
      break;
  
       /* resolve contention using the Ethernet address */
+ 
+      for (j = 0; j < 3; j++)
+      get_eeprom_data(id_port, j);
+ 
+      /* and save this address for later use */
+ 
       for (j = 0; j < 3; j++)
!      ep_board[neisa+nisa].eth_addr[j] = get_eeprom_data(id_port, j);
  
+      ep_board[neisa+nisa].res_cfg =
+     get_eeprom_data(id_port, EEPROM_RESOURCE_CFG);
+ 
+      ep_board[neisa+nisa].prod_id =
+     get_eeprom_data(id_port, EEPROM_PROD_ID);
+ 
+      ep_board[neisa].epb_isa = 1;
       ep_board[neisa+nisa].epb_used = 0;
       ep_board[neisa+nisa++].epb_addr =
!        (get_eeprom_data(id_port, EEPROM_ADDR_CFG) & 0x1f) * 0x10 + 0x200;
! 
       outb(id_port, ep_current_tag);  /* tags board */
       outb(id_port, ACTIVATE_ADAPTER_TO_CONFIG);
       ep_current_tag--;
***************
*** 266,283 ****
  
   IS_BASE=ep_board[i].epb_addr;
   ep_board[i].epb_used=1;
!  return 1;
      } else {
   for (i=0; ep_board[i].epb_addr && ep_board[i].epb_addr != IS_BASE; i++);
  
!  if( ep_board[i].epb_used || ep_board[i].epb_addr != IS_BASE)
       return 0;
  
   if (inw(IS_BASE + EP_W0_EEPROM_COMMAND) & EEPROM_TST_MODE)
       printf("ep%d: 3c5x9 at 0x%x in test mode. Erase pencil mark!\n",
         is->id_unit, IS_BASE);
   ep_board[i].epb_used=1;
!  return 1;
      }
  }
  
--- 299,318 ----
  
   IS_BASE=ep_board[i].epb_addr;
   ep_board[i].epb_used=1;
! 
!  return &ep_board[i];
      } else {
   for (i=0; ep_board[i].epb_addr && ep_board[i].epb_addr != IS_BASE; i++);
  
!  if( ep_board[i].epb_used || ep_board[i].epb_addr != IS_BASE) 
       return 0;
  
   if (inw(IS_BASE + EP_W0_EEPROM_COMMAND) & EEPROM_TST_MODE)
       printf("ep%d: 3c5x9 at 0x%x in test mode. Erase pencil mark!\n",
         is->id_unit, IS_BASE);
   ep_board[i].epb_used=1;
! 
!  return &ep_board[i];
      }
  }
  
***************
*** 308,327 ****
  
      ep_registerdev(is);
  
!     if (!ep_look_for_board_at(is))
   return (0);
      /*
       * The iobase was found and MFG_ID was 0x6d50. PROD_ID should be
       * 0x9[0-f]50
       */
      GO_WINDOW(0);
!     k = get_e(is, EEPROM_PROD_ID);
      if ((k & 0xf0ff) != (PROD_ID & 0xf0ff)) {
   printf("epprobe: ignoring model %04x\n", k);
   return (0);
      }
  
!     k = get_e(is, EEPROM_RESOURCE_CFG);
      k >>= 12;
  
      /* Now we have two cases again:
--- 343,363 ----
  
      ep_registerdev(is);
  
!     if(( sc->epb=ep_look_for_board_at(is) )==0)
   return (0);
      /*
       * The iobase was found and MFG_ID was 0x6d50. PROD_ID should be
       * 0x9[0-f]50
       */
      GO_WINDOW(0);
!     k = sc->epb->epb_isa ? sc->epb->prod_id : get_e(is, EEPROM_PROD_ID);
      if ((k & 0xf0ff) != (PROD_ID & 0xf0ff)) {
   printf("epprobe: ignoring model %04x\n", k);
   return (0);
      }
  
!     k = sc->epb->epb_isa ? sc->epb->res_cfg : get_e(is, EEPROM_RESOURCE_CFG);
! 
      k >>= 12;
  
      /* Now we have two cases again:
***************
*** 396,402 ****
      p = (u_short *) & sc->arpcom.ac_enaddr;
      for (i = 0; i < 3; i++) {
   GO_WINDOW(0);
!  p[i] = htons(get_e(is, i));
   GO_WINDOW(2);
   outw(BASE + EP_W2_ADDR_0 + (i * 2), ntohs(p[i]));
      }
--- 432,438 ----
      p = (u_short *) & sc->arpcom.ac_enaddr;
      for (i = 0; i < 3; i++) {
   GO_WINDOW(0);
!  p[i] = htons( sc->epb->epb_isa ? sc->epb->eth_addr[i] : get_e(is, i) );
   GO_WINDOW(2);
   outw(BASE + EP_W2_ADDR_0 + (i * 2), ntohs(p[i]));
      }
***************
*** 423,429 ****
      ifp->if_unit = is->id_unit;
      ifp->if_name = "ep";
      ifp->if_mtu = ETHERMTU;
!     ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
      ifp->if_init = epinit;
      ifp->if_output = ether_output;
      ifp->if_start = epstart;
--- 459,466 ----
      ifp->if_unit = is->id_unit;
      ifp->if_name = "ep";
      ifp->if_mtu = ETHERMTU;
!     ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | 
!  IFF_SIMPLEX | IFF_NOTRAILERS;
      ifp->if_init = epinit;
      ifp->if_output = ether_output;
      ifp->if_start = epstart;
***************
*** 432,438 ****
   ifp->if_timer=1;
  
      if_attach(ifp);
!     kdc_ep[is->id_unit].kdc_state = DC_BUSY;
  
      /*
       * Fill the hardware address into ifa_addr if we find an AF_LINK entry.
--- 469,477 ----
   ifp->if_timer=1;
  
      if_attach(ifp);
! 
!     /* device attach does transition from UNCONFIGURED to IDLE state */
!     kdc_ep[is->id_unit].kdc_state=DC_IDLE;
  
      /*
       * Fill the hardware address into ifa_addr if we find an AF_LINK entry.
***************
*** 475,481 ****
  #endif
      ep_fset(F_RX_FIRST);
      sc->top = sc->mcur = 0;
! 
  #if NBPFILTER > 0
      bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
  #endif
--- 514,520 ----
  #endif
      ep_fset(F_RX_FIRST);
      sc->top = sc->mcur = 0;
!  
  #if NBPFILTER > 0
      bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
  #endif
***************
*** 536,547 ****
  
      outw(BASE + EP_COMMAND, SET_INTR_MASK | S_5_INTS);
  
!  if(ifp->if_flags & IFF_PROMISC)
!     outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL |
!      FIL_GROUP | FIL_BRDCST | FIL_ALL);
!  else
!     outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL |
!      FIL_GROUP | FIL_BRDCST);
  
    /*
     * S.B.
--- 575,586 ----
  
      outw(BASE + EP_COMMAND, SET_INTR_MASK | S_5_INTS);
  
!     if(ifp->if_flags & IFF_PROMISC)
!  outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL |
!   FIL_GROUP | FIL_BRDCST | FIL_ALL);
!     else
!  outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL |
!   FIL_GROUP | FIL_BRDCST);
  
    /*
     * S.B.
***************
*** 814,820 ****
         sc->rx_no_first, sc->rx_no_mbuf, sc->rx_bpf_disc, sc->rx_overrunf,
         sc->rx_overrunl, sc->tx_underrun);
  #else
!      printf("ep%d: Status: %x\n", unit, status);
  #endif
       epinit(unit);
       splx(x);
--- 853,865 ----
         sc->rx_no_first, sc->rx_no_mbuf, sc->rx_bpf_disc, sc->rx_overrunf,
         sc->rx_overrunl, sc->tx_underrun);
  #else
! 
! #ifdef nightmaremessages
!      printf("ep%d: Status: %x (input buffer overflow)\n", unit, status);
! #else
!      ++sc->arpcom.ac_if.if_ierrors;
! #endif
! 
  #endif
       epinit(unit);
       splx(x);
***************
*** 1129,1139 ****
      struct ifreq *ifr = (struct ifreq *) data;
      int s, error = 0;
  
!     s = splimp();
  
      switch (cmd) {
        case SIOCSIFADDR:
   ifp->if_flags |= IFF_UP;
   switch (ifa->ifa_addr->sa_family) {
  #ifdef INET
     case AF_INET:
--- 1174,1188 ----
      struct ifreq *ifr = (struct ifreq *) data;
      int s, error = 0;
  
!     s=splimp();
  
      switch (cmd) {
        case SIOCSIFADDR:
   ifp->if_flags |= IFF_UP;
+ 
+  /* netifs are BUSY when UP */
+  kdc_ep[ifp->if_unit].kdc_state=DC_BUSY;
+ 
   switch (ifa->ifa_addr->sa_family) {
  #ifdef INET
     case AF_INET:
***************
*** 1159,1179 ****
      break;
       }
  #endif
     default:
       epinit(ifp->if_unit);
       break;
   }
   break;
        case SIOCGIFADDR:
!  { 
!    struct sockaddr *sa; 
!  
!    sa = (struct sockaddr *) & ifr->ifr_data;
!    bcopy((caddr_t) sc->arpcom.ac_enaddr, 
      (caddr_t) sa->sa_data, ETHER_ADDR_LEN);
   }
   break;
        case SIOCSIFFLAGS:
   if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) {
       ifp->if_flags &= ~IFF_RUNNING;
       epstop(ifp->if_unit);
--- 1208,1251 ----
      break;
       }
  #endif
+ #ifdef IPX
+    case AF_IPX:
+      {
+     register struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
+ 
+     if (ipx_nullhost(*ina))
+         ina->x_host =
+        *(union ipx_host *) (sc->arpcom.ac_enaddr);
+     else {
+         ifp->if_flags &= ~IFF_RUNNING;
+         bcopy((caddr_t) ina->x_host.c_host,
+          (caddr_t) sc->arpcom.ac_enaddr,
+          sizeof(sc->arpcom.ac_enaddr));
+     }
+     epinit(ifp->if_unit);
+     break;
+      }
+ #endif
     default:
       epinit(ifp->if_unit);
       break;
   }
   break;
        case SIOCGIFADDR:
!  {
!  struct sockaddr *sa;
! 
!  sa = (struct sockaddr *) & ifr->ifr_data;
!  bcopy((caddr_t) sc->arpcom.ac_enaddr,
      (caddr_t) sa->sa_data, ETHER_ADDR_LEN);
   }
   break;
        case SIOCSIFFLAGS:
+  /* UP controls BUSY/IDLE */
+  kdc_ep[ifp->if_unit].kdc_state= ( (ifp->if_flags & IFF_UP)
+     ? DC_BUSY
+     : DC_IDLE );
+ 
   if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) {
       ifp->if_flags &= ~IFF_RUNNING;
       epstop(ifp->if_unit);
***************
*** 1186,1191 ****
--- 1258,1264 ----
   }
  
   /* NOTREACHED */
+ #if 0
  
   if (ifp->if_flags & IFF_UP && (ifp->if_flags & IFF_RUNNING) == 0)
       epinit(ifp->if_unit);
***************
*** 1198,1203 ****
--- 1271,1277 ----
       ep_frst(F_PROMISC);
       epinit(ifp->if_unit);
       }
+ #endif
  
   break;
  #ifdef notdef
***************
*** 1216,1223 ****
      } else {
         ifp->if_mtu = ifr->ifr_mtu;
      }
!     break;
! 
        default:
      error = EINVAL;
      }
--- 1290,1304 ----
      } else {
         ifp->if_mtu = ifr->ifr_mtu;
      }
!     break; 
!  case SIOCADDMULTI:
!  case SIOCDELMULTI:
!      /* Now this driver has no support for programmable
!       * multicast filters. If some day it will gain this
!       * support this part of code must be extended.
!       */
!      error=0;
!      break;
        default:
      error = EINVAL;
      }
*** if_epreg.h Mon Oct 23 08:25:55 1995
--- /sys/i386/isa/if_epreg.h  Fri Aug  4 09:00:36 1995
***************
*** 71,76 ****
--- 70,77 ----
  
  #define         F_ACCESS_32_BITS 0x100
  
+     struct ep_board *epb;
+ 
  #ifdef  EP_LOCAL_STATS
      short tx_underrun;
      short rx_no_first;
***************
*** 80,85 ****
--- 81,97 ----
      short rx_overrunl;
  #endif
  };
+ 
+ struct ep_board {
+  int epb_addr;  /* address of this board */
+  char epb_used; /* was this entry already used for configuring ? */
+           /* data from EEPROM for later use */
+  char epb_isa;  /* flag: this is an ISA card */
+  u_short eth_addr[3]; /* Ethernet address */
+  u_short prod_id;  /* product ID */
+  u_short res_cfg;  /* resource configuration */
+  };
+ 
  
  /*
   * Some global constants
=============== CUT HERE =============================