+static void adm8211_configure_filter(struct ieee80211_hw *dev,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count, struct dev_mc_list *mclist)
+{
+ static const u8 bcast[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+ struct adm8211_priv *priv = dev->priv;
+ unsigned int bit_nr, new_flags;
+ u32 mc_filter[2];
+ int i;
+
+ new_flags = 0;
+
+ if (*total_flags & FIF_PROMISC_IN_BSS) {
+ new_flags |= FIF_PROMISC_IN_BSS;
+ priv->nar |= ADM8211_NAR_PR;
+ priv->nar &= ~ADM8211_NAR_MM;
+ mc_filter[1] = mc_filter[0] = ~0;
+ } else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32)) {
+ new_flags |= FIF_ALLMULTI;
+ priv->nar &= ~ADM8211_NAR_PR;
+ priv->nar |= ADM8211_NAR_MM;
+ mc_filter[1] = mc_filter[0] = ~0;
+ } else {
+ priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR);
+ mc_filter[1] = mc_filter[0] = 0;
+ for (i = 0; i < mc_count; i++) {
+ if (!mclist)
+ break;
+ bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+
+ bit_nr &= 0x3F;
+ mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
+ mclist = mclist->next;
+ }
+ }
+
+ ADM8211_IDLE_RX();
+
+ ADM8211_CSR_WRITE(MAR0, mc_filter[0]);
+ ADM8211_CSR_WRITE(MAR1, mc_filter[1]);
+ ADM8211_CSR_READ(NAR);
+
+ if (priv->nar & ADM8211_NAR_PR)
+ dev->flags |= IEEE80211_HW_RX_INCLUDES_FCS;
+ else
+ dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS;
+
+ if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
+ adm8211_set_bssid(dev, bcast);
+ else
+ adm8211_set_bssid(dev, priv->bssid);
+
+ ADM8211_RESTORE();
+
+ *total_flags = new_flags;
+}
+