📄 wavelan.c
字号:
printk(" MHz\n");#endif /* DEBUG_BASIC_SHOW */#ifdef DEBUG_VERSION_SHOW /* Print version information */ printk(KERN_NOTICE "%s", version);#endif} /* wv_init_info *//********************* IOCTL, STATS & RECONFIG *********************//* * We found here routines that are called by Linux on different * occasions after the configuration and not for transmitting data * These may be called when the user use ifconfig, /proc/net/dev * or wireless extensions *//*------------------------------------------------------------------*//* * Get the current Ethernet statistics. This may be called with the * card open or closed. * Used when the user read /proc/net/dev */static en_stats *wavelan_get_stats(struct net_device * dev){#ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name);#endif return (&((net_local *) dev->priv)->stats);}/*------------------------------------------------------------------*//* * Set or clear the multicast filter for this adaptor. * num_addrs == -1 Promiscuous mode, receive all packets * num_addrs == 0 Normal mode, clear multicast list * num_addrs > 0 Multicast mode, receive normal and MC packets, * and do best-effort filtering. */static void wavelan_set_multicast_list(struct net_device * dev){ net_local *lp = (net_local *) dev->priv;#ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n", dev->name);#endif#ifdef DEBUG_IOCTL_INFO printk(KERN_DEBUG "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n", dev->name, dev->flags, dev->mc_count);#endif /* Are we asking for promiscuous mode, * or all multicast addresses (we don't have that!) * or too many multicast addresses for the hardware filter? */ if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) || (dev->mc_count > I82586_MAX_MULTICAST_ADDRESSES)) { /* * Enable promiscuous mode: receive all packets. */ if (!lp->promiscuous) { lp->promiscuous = 1; lp->mc_count = 0; wv_82586_reconfig(dev); /* Tell the kernel that we are doing a really bad job. */ dev->flags |= IFF_PROMISC; } } else /* Are there multicast addresses to send? */ if (dev->mc_list != (struct dev_mc_list *) NULL) { /* * Disable promiscuous mode, but receive all packets * in multicast list */#ifdef MULTICAST_AVOID if (lp->promiscuous || (dev->mc_count != lp->mc_count))#endif { lp->promiscuous = 0; lp->mc_count = dev->mc_count; wv_82586_reconfig(dev); } } else { /* * Switch to normal mode: disable promiscuous mode and * clear the multicast list. */ if (lp->promiscuous || lp->mc_count == 0) { lp->promiscuous = 0; lp->mc_count = 0; wv_82586_reconfig(dev); } }#ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: <-wavelan_set_multicast_list()\n", dev->name);#endif}/*------------------------------------------------------------------*//* * This function doesn't exist. * (Note : it was a nice way to test the reconfigure stuff...) */#ifdef SET_MAC_ADDRESSstatic int wavelan_set_mac_address(struct net_device * dev, void *addr){ struct sockaddr *mac = addr; /* Copy the address. */ memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE); /* Reconfigure the beast. */ wv_82586_reconfig(dev); return 0;}#endif /* SET_MAC_ADDRESS */#ifdef WIRELESS_EXT /* if wireless extensions exist in the kernel *//*------------------------------------------------------------------*//* * Frequency setting (for hardware capable of it) * It's a bit complicated and you don't really want to look into it. * (called in wavelan_ioctl) */static inline int wv_set_frequency(unsigned long ioaddr, /* I/O port of the card */ iw_freq * frequency){ const int BAND_NUM = 10; /* Number of bands */ long freq = 0L; /* offset to 2.4 GHz in .5 MHz */#ifdef DEBUG_IOCTL_INFO int i;#endif /* Setting by frequency */ /* Theoretically, you may set any frequency between * the two limits with a 0.5 MHz precision. In practice, * I don't want you to have trouble with local regulations. */ if ((frequency->e == 1) && (frequency->m >= (int) 2.412e8) && (frequency->m <= (int) 2.487e8)) { freq = ((frequency->m / 10000) - 24000L) / 5; } /* Setting by channel (same as wfreqsel) */ /* Warning: each channel is 22 MHz wide, so some of the channels * will interfere. */ if ((frequency->e == 0) && (frequency->m < BAND_NUM)) { /* Get frequency offset. */ freq = channel_bands[frequency->m] >> 1; } /* Verify that the frequency is allowed. */ if (freq != 0L) { u16 table[10]; /* Authorized frequency table */ /* Read the frequency table. */ fee_read(ioaddr, 0x71, table, 10);#ifdef DEBUG_IOCTL_INFO printk(KERN_DEBUG "Frequency table: "); for (i = 0; i < 10; i++) { printk(" %04X", table[i]); } printk("\n");#endif /* Look in the table to see whether the frequency is allowed. */ if (!(table[9 - ((freq - 24) / 16)] & (1 << ((freq - 24) % 16)))) return -EINVAL; /* not allowed */ } else return -EINVAL; /* if we get a usable frequency */ if (freq != 0L) { unsigned short area[16]; unsigned short dac[2]; unsigned short area_verify[16]; unsigned short dac_verify[2]; /* Corresponding gain (in the power adjust value table) * See AT&T WaveLAN Data Manual, REF 407-024689/E, page 3-8 * and WCIN062D.DOC, page 6.2.9. */ unsigned short power_limit[] = { 40, 80, 120, 160, 0 }; int power_band = 0; /* Selected band */ unsigned short power_adjust; /* Correct value */ /* Search for the gain. */ power_band = 0; while ((freq > power_limit[power_band]) && (power_limit[++power_band] != 0)); /* Read the first area. */ fee_read(ioaddr, 0x00, area, 16); /* Read the DAC. */ fee_read(ioaddr, 0x60, dac, 2); /* Read the new power adjust value. */ fee_read(ioaddr, 0x6B - (power_band >> 1), &power_adjust, 1); if (power_band & 0x1) power_adjust >>= 8; else power_adjust &= 0xFF;#ifdef DEBUG_IOCTL_INFO printk(KERN_DEBUG "WaveLAN EEPROM Area 1: "); for (i = 0; i < 16; i++) { printk(" %04X", area[i]); } printk("\n"); printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n", dac[0], dac[1]);#endif /* Frequency offset (for info only) */ area[0] = ((freq << 5) & 0xFFE0) | (area[0] & 0x1F); /* Receiver Principle main divider coefficient */ area[3] = (freq >> 1) + 2400L - 352L; area[2] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); /* Transmitter Main divider coefficient */ area[13] = (freq >> 1) + 2400L; area[12] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); /* Other parts of the area are flags, bit streams or unused. */ /* Set the value in the DAC. */ dac[1] = ((power_adjust >> 1) & 0x7F) | (dac[1] & 0xFF80); dac[0] = ((power_adjust & 0x1) << 4) | (dac[0] & 0xFFEF); /* Write the first area. */ fee_write(ioaddr, 0x00, area, 16); /* Write the DAC. */ fee_write(ioaddr, 0x60, dac, 2); /* We now should verify here that the writing of the EEPROM went OK. */ /* Reread the first area. */ fee_read(ioaddr, 0x00, area_verify, 16); /* Reread the DAC. */ fee_read(ioaddr, 0x60, dac_verify, 2); /* Compare. */ if (memcmp(area, area_verify, 16 * 2) || memcmp(dac, dac_verify, 2 * 2)) {#ifdef DEBUG_IOCTL_ERROR printk(KERN_INFO "WaveLAN: wv_set_frequency: unable to write new frequency to EEPROM(?).\n");#endif return -EOPNOTSUPP; } /* We must download the frequency parameters to the * synthesizers (from the EEPROM - area 1) * Note: as the EEPROM is automatically decremented, we set the end * if the area... */ mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x0F); mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); /* Wait until the download is finished. */ fee_wait(ioaddr, 100, 100); /* We must now download the power adjust value (gain) to * the synthesizers (from the EEPROM - area 7 - DAC). */ mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x61); mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); /* Wait for the download to finish. */ fee_wait(ioaddr, 100, 100);#ifdef DEBUG_IOCTL_INFO /* Verification of what we have done */ printk(KERN_DEBUG "WaveLAN EEPROM Area 1: "); for (i = 0; i < 16; i++) { printk(" %04X", area_verify[i]); } printk("\n"); printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n", dac_verify[0], dac_verify[1]);#endif return 0; } else return -EINVAL; /* Bah, never get there... */}/*------------------------------------------------------------------*//* * Give the list of available frequencies. */static inline int wv_frequency_list(unsigned long ioaddr, /* I/O port of the card */ iw_freq * list, /* List of frequencies to fill */ int max){ /* Maximum number of frequencies */ u16 table[10]; /* Authorized frequency table */ long freq = 0L; /* offset to 2.4 GHz in .5 MHz + 12 MHz */ int i; /* index in the table */ int c = 0; /* Channel number */ /* Read the frequency table. */ fee_read(ioaddr, 0x71 /* frequency table */ , table, 10); /* Check all frequencies. */ i = 0; for (freq = 0; freq < 150; freq++) /* Look in the table if the frequency is allowed */ if (table[9 - (freq / 16)] & (1 << (freq % 16))) { /* Compute approximate channel number */ while ((((channel_bands[c] >> 1) - 24) < freq) && (c < NELS(channel_bands))) c++; list[i].i = c; /* Set the list index */ /* put in the list */ list[i].m = (((freq + 24) * 5) + 24000L) * 10000; list[i++].e = 1; /* Check number. */ if (i >= max) return (i); } return (i);}#ifdef IW_WIRELESS_SPY/*------------------------------------------------------------------*//* * Gather wireless spy statistics: for each packet, compare the source * address with our list, and if they match, get the statistics. * Sorry, but this function really needs the wireless extensions. */static inline void wl_spy_gather(struct net_device * dev, u8 * mac, /* MAC address */ u8 * stats) /* Statistics to gather */{ struct iw_quality wstats; wstats.qual = stats[2] & MMR_SGNL_QUAL; wstats.level = stats[0] & MMR_SIGNAL_LVL; wstats.noise = stats[1] & MMR_SILENCE_LVL; wstats.updated = 0x7; /* Update spy records */ wireless_spy_update(dev, mac, &wstats);}#endif /* IW_WIRELESS_SPY */#ifdef HISTOGRAM/*------------------------------------------------------------------*//* * This function calculates a histogram of the signal level. * As the noise is quite constant, it's like doing it on the SNR. * We have defined a set of interval (lp->his_range), and each time * the level goes in that interval, we increment the count (lp->his_sum). * With this histogram you may detect if one WaveLAN is really weak, * or you may also calculate the mean and standard deviation of the level. */static inline void wl_his_gather(struct net_device * dev, u8 * stats){ /* Statistics to gather */ net_local *lp = (net_local *) dev->priv; u8 level = stats[0] & MMR_SIGNAL_LVL; int i; /* Find the correct interval. */ i = 0; while ((i < (lp->his_number - 1)) && (level >= lp->his_range[i++])); /* Increment interval counter. */ (lp->his_sum[i])++;}#endif /* HISTOGRAM *//*------------------------------------------------------------------*//* * Wireless Handler : get protocol name */static int wavelan_get_name(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ strcpy(wrqu->name, "WaveLAN"); return 0;}/*------------------------------------------------------------------*//* * Wireless Handler : set NWID */static int wavelan_set_nwid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ unsigned long ioaddr = dev->base_addr; net_local *lp = (net_local *) dev->priv; /* lp is not unused */ psa_t psa; mm_t m; unsigned long flags; int ret = 0; /* Disable interrupts and save flags. */ spin_lock_irqsave(&lp->spinlock, flags); /* Set NWID in WaveLAN. */ if (!wrqu->nwid.disabled) { /* Set NWID in psa */ psa.psa_nwid[0] = (wrqu->nwid.value & 0xFF00) >> 8; psa.psa_nwid[1] = wrqu->nwid.value & 0xFF; psa.psa_nwid_select = 0x01; psa_write(ioaddr, lp->hacr, (char *) psa.psa_nwid - (char *) &psa, (unsigned char *) psa.psa_nwid, 3); /* Set NWID in mmc. */ m.w.mmw_netw_id_l = psa.psa_nwid[1]; m.w.mmw_netw_id_h = psa.psa_nwid[0]; mmc_write(ioaddr, (char *) &m.w.mmw_netw_id_l - (char *) &m, (unsigned char *) &m.w.mmw_netw_id_l, 2); mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), 0x00); } else { /* Disable NWID in the psa. */ psa.psa_nwid_select = 0x00; psa_write(ioaddr, lp->hacr, (char *) &psa.psa_nwid_select - (char *) &psa, (unsigned char *) &psa.psa_nwid_select, 1); /* Disable NWID in the mmc (no filtering). */ mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), MMW_LOOPT_SEL_DIS_NWID); } /* update the Wavelan checksum */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -