📄 wavelan.c
字号:
/*------------------------------------------------------------------*//* * 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(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 voidwavelan_set_multicast_list(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 /* If we ask for promiscuous mode, * or all multicast addresses (we don't have that !) * or too much 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 /* If there is some 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... */static intwavelan_set_mac_address(device * dev, void * addr){ struct sockaddr * mac = addr; /* Copy the address */ memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE); /* Reconfig the beast */ wv_82586_reconfig(dev); return 0;}#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel *//*------------------------------------------------------------------*//* * Frequency setting (for hardware able of it) * It's a bit complicated and you don't really want to look into it... * (called in wavelan_ioctl) */static inline intwv_set_frequency(u_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 22MHz wide, so some of the channels * will interfere... */ if((frequency->e == 0) && (frequency->m >= 0) && (frequency->m < BAND_NUM)) { /* frequency in 1/4 of MHz (as read in the offset register) */ short bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8, 0xD0, 0xF0, 0xF8, 0x150 }; /* Get frequency offset */ freq = bands[frequency->m] >> 1; } /* Verify if the frequency is allowed */ if(freq != 0L) { u_short table[10]; /* Authorized frequency table */ /* Read the frequency table */ fee_read(ioaddr, 0x71 /* frequency table */, 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 if 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 * & 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); /* Others part 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 EEPROM writing was 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 until the download is finished */ 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 intwv_frequency_list(u_long ioaddr, /* i/o port of the card */ iw_freq * list, /* List of frequency to fill */ int max) /* Maximum number of frequencies */{ u_short table[10]; /* Authorized frequency table */ long freq = 0L; /* offset to 2.4 GHz in .5 MHz + 12 MHz */ int i; /* index in the table */ /* Read the frequency table */ fee_read(ioaddr, 0x71 /* frequency table */, table, 10); /* Look 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))) { /* 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 WIRELESS_SPY/*------------------------------------------------------------------*//* * Gather wireless spy statistics : for each packet, compare the source * address with out list, and if match, get the stats... * Sorry, but this function really need wireless extensions... */static inline voidwl_spy_gather(device * dev, u_char * mac, /* MAC address */ u_char * stats) /* Statistics to gather */{ net_local * lp = (net_local *) dev->priv; int i; /* Look all addresses */ for(i = 0; i < lp->spy_number; i++) /* If match */ if(!memcmp(mac, lp->spy_address[i], WAVELAN_ADDR_SIZE)) { /* Update statistics */ lp->spy_stat[i].qual = stats[2] & MMR_SGNL_QUAL; lp->spy_stat[i].level = stats[0] & MMR_SIGNAL_LVL; lp->spy_stat[i].noise = stats[1] & MMR_SILENCE_LVL; lp->spy_stat[i].updated = 0x7; }}#endif /* WIRELESS_SPY */#ifdef HISTOGRAM/*------------------------------------------------------------------*//* * This function calculates an histogram on 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 voidwl_his_gather(device * dev, u_char * stats) /* Statistics to gather */{ net_local * lp = (net_local *) dev->priv; u_char 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 *//*------------------------------------------------------------------*//* * Perform ioctl : config & info stuff * This is here that are treated the wireless extensions (iwconfig) */static intwavelan_ioctl(struct device * dev, /* device on which the ioctl is applied */ struct ifreq * rq, /* data passed */ int cmd) /* ioctl number */{ u_long ioaddr = dev->base_addr; net_local * lp = (net_local *)dev->priv; /* lp is not unused */ struct iwreq * wrq = (struct iwreq *) rq; psa_t psa; mm_t m; unsigned long x; int ret = 0;#ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd);#endif /* Disable interrupts & save flags */ x = wv_splhi(); /* Look what is the request */ switch(cmd) { /* --------------- WIRELESS EXTENSIONS --------------- */ case SIOCGIWNAME: strcpy(wrq->u.name, "Wavelan"); break; case SIOCSIWNWID: /* Set NWID in WaveLAN */ if(wrq->u.nwid.on) { /* Set NWID in psa */ psa.psa_nwid[0] = (wrq->u.nwid.nwid & 0xFF00) >> 8; psa.psa_nwid[1] = wrq->u.nwid.nwid & 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 = wrq->u.nwid.nwid & 0xFF; m.w.mmw_netw_id_h = (wrq->u.nwid.nwid & 0xFF00) >> 8; 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); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -