diff -r -u5 -N -x CVS /cygdrive/w/Share/anon_cvs/ecos/packages/devs/eth/ns/dp83902a/current/ChangeLog /cygdrive/c/development/ecos/packages/devs/eth/ns/dp83902a/current/ChangeLog
--- /cygdrive/w/Share/anon_cvs/ecos/packages/devs/eth/ns/dp83902a/current/ChangeLog	2004-08-12 21:01:17.000000000 +0800
+++ /cygdrive/c/development/ecos/packages/devs/eth/ns/dp83902a/current/ChangeLog	2007-02-02 15:23:34.722191000 +0800
@@ -1,5 +1,13 @@
+2007-02-02  Wang Cui <iucgnaw@msn.com>
+
+	* cdl/ns_dp83902a_eth_drivers.cdl: Implements CYGINT_IO_ETH_MULTICAST.
+	* src/if_dp83902a.c: Added support for ETH_DRV_SET_MC_ALL, ETH_DRV_SET_MC_LIST.
+	                     Added support for ETH_DRV_SET_MAC_ADDRESS.
+	                     Fixed warnings.
+	                     Other minor modification.
+
 2004-08-12  Jani Monoses <jani@iv.ro>
 
 	* src/if_dp83902a.c: Fix builing with lwip.
 
 2003-11-19  David Woodhouse  <dwmw2@redhat.com>
diff -r -u5 -N -x CVS /cygdrive/w/Share/anon_cvs/ecos/packages/devs/eth/ns/dp83902a/current/cdl/ns_dp83902a_eth_drivers.cdl /cygdrive/c/development/ecos/packages/devs/eth/ns/dp83902a/current/cdl/ns_dp83902a_eth_drivers.cdl
--- /cygdrive/w/Share/anon_cvs/ecos/packages/devs/eth/ns/dp83902a/current/cdl/ns_dp83902a_eth_drivers.cdl	2002-05-24 07:00:46.000000000 +0800
+++ /cygdrive/c/development/ecos/packages/devs/eth/ns/dp83902a/current/cdl/ns_dp83902a_eth_drivers.cdl	2007-02-02 12:17:01.925316000 +0800
@@ -53,10 +53,11 @@
 
     parent        CYGPKG_IO_ETH_DRIVERS
     active_if     CYGPKG_IO_ETH_DRIVERS
 
     implements    CYGHWR_NET_DRIVERS
+    implements    CYGINT_IO_ETH_MULTICAST
 
     active_if     CYGINT_DEVS_ETH_NS_DP83902A_REQUIRED
 
     include_dir   cyg/io
     description   "Ethernet driver for NS DP83902A (and DP8390) ethernet controller."
diff -r -u5 -N -x CVS /cygdrive/w/Share/anon_cvs/ecos/packages/devs/eth/ns/dp83902a/current/src/if_dp83902a.c /cygdrive/c/development/ecos/packages/devs/eth/ns/dp83902a/current/src/if_dp83902a.c
--- /cygdrive/w/Share/anon_cvs/ecos/packages/devs/eth/ns/dp83902a/current/src/if_dp83902a.c	2004-08-12 21:01:17.000000000 +0800
+++ /cygdrive/c/development/ecos/packages/devs/eth/ns/dp83902a/current/src/if_dp83902a.c	2007-02-02 15:22:11.144066000 +0800
@@ -164,18 +164,27 @@
         for (i = 0; i < 6; i++)
             DP_IN(base, DP_P1_PAR0+i, dp->esa[i]);
     }
     DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0);  // Select page 0
 
+#if DEBUG & 1
     diag_printf("DP83902A - %s ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
                 (dp->hardwired_esa) ? "static" : "eeprom",
                 dp->esa[0],
                 dp->esa[1],
                 dp->esa[2],
                 dp->esa[3],
                 dp->esa[4],
                 dp->esa[5] );
+#endif
+
+    // Prepare multicast filter.
+    DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1);
+    for (i = 0; i < 8; i++) {
+        DP_OUT(base, DP_P1_MAR0+i, 0x00);
+    }
+    DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0);
 
 #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
     cyg_drv_interrupt_create(
         dp->interrupt,
         0,                  // Priority - unused
@@ -250,26 +259,123 @@
         DP_OUT(base, DP_P1_PAR0+i, enaddr[i]);
     }
     // Enable and start device
     DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);  
     DP_OUT(base, DP_TCR, DP_TCR_NORMAL); // Normal transmit operations
-    DP_OUT(base, DP_RCR, DP_RCR_AB);  // Accept broadcast, no errors, no multicast
+    DP_OUT(base, DP_RCR, DP_RCR_AB | DP_RCR_AM); // Accept broadcast, accept multicast, no errors
     dp->running = true;
     CR_DOWN();
 }
 
 //
+// Compute crc for ethernet address
+//
+static cyg_uint32
+dp83902a_crc(cyg_uint8 *p_mac_addr)
+{
+#define POLYNOMIAL 0x04c11db6
+    cyg_uint32 crc = 0xffffffff;
+    int carry, i, j;
+    cyg_uint8 b;
+
+    DEBUG_FUNCTION();
+
+    for (i = 6; --i >= 0;) {
+        b = *p_mac_addr++;
+        for (j = 8; --j >= 0;) {
+            carry = ((crc & 0x80000000) ? 1 : 0) ^ (b & 0x01);
+            crc <<= 1;
+            b >>= 1;
+            if (carry)
+                crc = (crc ^ POLYNOMIAL) | carry;
+        }
+    }
+    return crc;
+#undef POLYNOMIAL
+}
+
+//
 // This routine is called to perform special "control" opertions
 //
 static int
 dp83902a_control(struct eth_drv_sc *sc, unsigned long key,
                void *data, int data_len)
 {
+    dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *)sc->driver_private;
+    cyg_uint8 *base = dp->base;
+
+    DEBUG_FUNCTION();
+
     switch (key) {
     case ETH_DRV_SET_MAC_ADDRESS:
-        return 0;
+        {
+            int i_par;
+            cyg_uint8 *esa = (cyg_uint8 *)data;
+            
+            DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_STOP);
+            
+            DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1);
+            for (i_par = 0;  i_par < ETHER_ADDR_LEN;  i_par++) {
+                DP_OUT(base, DP_P1_PAR0+i_par, esa[i_par]);
+            }
+            DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0);
+
+            DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_START);
+            return 0;
+        }
+        break;
+        
+    case ETH_DRV_SET_MC_ALL:
+        {
+            int i_mar;
+
+            DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_STOP);
+            
+            DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1);
+            for (i_mar = 0; i_mar < 8; i_mar++) {
+                DP_OUT(base, DP_P1_MAR0+i_mar, 0xFF);
+            }
+            DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0);
+
+            DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_START);
+            return 0;
+        }
+        break;
+            
+    case ETH_DRV_SET_MC_LIST:
+        {
+            int i_mc_list, i_mar;
+            struct eth_drv_mc_list *p_mc_list = (struct eth_drv_mc_list *)(data);
+            cyg_uint32 result;
+
+            DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_STOP);
+            
+            for (i_mc_list = 0; i_mc_list < p_mc_list->len; ++i_mc_list) {
+                cyg_uint8 marx;
+                cyg_uint8 mcaf[8];
+
+                // Clear temp multicast address filter.
+                mcaf[0] = 0x00; mcaf[1] = 0x00; mcaf[2] = 0x00; mcaf[3] = 0x00;
+                mcaf[4] = 0x00; mcaf[5] = 0x00; mcaf[6] = 0x00; mcaf[7] = 0x00;
+                // Hash this multicast address.
+                result = dp83902a_crc(&p_mc_list->addrs[i_mc_list][0]) >> 26;
+                mcaf[result >> 3] |= 1 << (result & 7);
+
+                DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1);
+                for (i_mar = 0; i_mar < 8; i_mar++) {
+                    DP_IN (base, DP_P1_MAR0+i_mar, marx);
+                    marx |= mcaf[i_mar];
+                    DP_OUT(base, DP_P1_MAR0+i_mar, marx);
+                }
+                DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0);
+            }
+
+            DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_START);
+            return 0;
+        }
         break;
+        
     default:
         return 1;
         break;
     }
 }
@@ -401,11 +507,11 @@
     // Put data into buffer
     for (i = 0;  i < sg_len;  i++) {
         data = (unsigned char *)sg_list[i].buf;
         len = sg_list[i].len;
 #if DEBUG & 4
-        diag_printf(" sg buf %08x len %08x\n ", data, len);
+        diag_printf(" sg buf %08x len %08x\n ", (unsigned int)(data), len);
         dx = 0;
 #endif
         while (len > 0) {
 #ifdef CYGHWR_NS_DP83902A_PLF_16BIT_DATA
             cyg_uint16 tmp;
@@ -601,11 +707,11 @@
     for (i = 0;  i < sg_len;  i++) {
         data = (unsigned char *)sg_list[i].buf;
         if (data) {
             mlen = sg_list[i].len;
 #if DEBUG & 4
-            diag_printf(" sg buf %08x len %08x \n", data, mlen);
+            diag_printf(" sg buf %08x len %08x \n", (unsigned int)(data), mlen);
             dx = 0;
 #endif
             while (0 < mlen) {
                 // Saved byte from previous loop?
                 if (saved) {
