📄 wavelan_cs.c
字号:
#ifdef DEBUG_I82593_SHOW wv_ru_show(dev);#endif#ifdef DEBUG_BASIC_SHOW /* Now, let's go for the basic stuff */ printk(KERN_NOTICE "%s: WaveLAN: port %#x, irq %d, hw_addr", dev->name, base, dev->irq); for(i = 0; i < WAVELAN_ADDR_SIZE; i++) printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]); /* Print current network id */ if(psa.psa_nwid_select) printk(", nwid 0x%02X-%02X", psa.psa_nwid[0], psa.psa_nwid[1]); else printk(", nwid off"); /* If 2.00 card */ if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { unsigned short freq; /* Ask the EEprom to read the frequency from the first area */ fee_read(base, 0x00 /* 1st area - frequency... */, &freq, 1); /* Print frequency */ printk(", 2.00, %ld", (freq >> 6) + 2400L); /* Hack !!! */ if(freq & 0x20) printk(".5"); } else { printk(", PCMCIA, "); switch (psa.psa_subband) { case PSA_SUBBAND_915: printk("915"); break; case PSA_SUBBAND_2425: printk("2425"); break; case PSA_SUBBAND_2460: printk("2460"); break; case PSA_SUBBAND_2484: printk("2484"); break; case PSA_SUBBAND_2430_5: printk("2430.5"); break; default: printk("unknown"); } } 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 differents * 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(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(dev->flags & IFF_PROMISC) { /* * Enable promiscuous mode: receive all packets. */ if(!lp->promiscuous) { lp->promiscuous = 1; lp->allmulticast = 0; lp->mc_count = 0; wv_82593_reconfig(dev); /* Tell the kernel that we are doing a really bad job... */ dev->flags |= IFF_PROMISC; } } else /* If all multicast addresses * or too much multicast addresses for the hardware filter */ if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > I82593_MAX_MULTICAST_ADDRESSES)) { /* * Disable promiscuous mode, but active the all multicast mode */ if(!lp->allmulticast) { lp->promiscuous = 0; lp->allmulticast = 1; lp->mc_count = 0; wv_82593_reconfig(dev); /* Tell the kernel that we are doing a really bad job... */ dev->flags |= IFF_ALLMULTI; } } 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 || lp->allmulticast || (dev->mc_count != lp->mc_count))#endif { lp->promiscuous = 0; lp->allmulticast = 0; lp->mc_count = dev->mc_count; wv_82593_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->allmulticast = 0; lp->mc_count = 0; wv_82593_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 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_82593_reconfig(dev); return 0;}#endif /* SET_MAC_ADDRESS */#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 base, /* 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 */ /* Theoritically, 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)) { /* Get frequency offset. */ freq = channel_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(base, 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(base, 0x00, area, 16); /* Read the DAC */ fee_read(base, 0x60, dac, 2); /* Read the new power adjust value */ fee_read(base, 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(base, 0x00, area, 16); /* Write the DAC */ fee_write(base, 0x60, dac, 2); /* We now should verify here that the EEprom writting was ok */ /* ReRead the first area */ fee_read(base, 0x00, area_verify, 16); /* ReRead the DAC */ fee_read(base, 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 * synthetisers (from the EEprom - area 1) * Note : as the EEprom is auto decremented, we set the end * if the area... */ mmc_out(base, mmwoff(0, mmw_fee_addr), 0x0F); mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); /* Wait until the download is finished */ fee_wait(base, 100, 100); /* We must now download the power adjust value (gain) to * the synthetisers (from the EEprom - area 7 - DAC) */ mmc_out(base, mmwoff(0, mmw_fee_addr), 0x61); mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); /* Wait until the download is finished */ fee_wait(base, 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 base, /* 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 */#if WIRELESS_EXT > 7 const int BAND_NUM = 10; /* Number of bands */ int c = 0; /* Channel number */#endif /* WIRELESS_EXT */ /* Read the frequency table */ fee_read(base, 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))) {#if WIRELESS_EXT > 7 /* Compute approximate channel number */ while((((channel_bands[c] >> 1) - 24) < freq) && (c < BAND_NUM)) c++; list[i].i = c; /* Set the list index */#endif /* WIRELESS_EXT */ /* put in the list */ list[i].m = (((freq + 24) * 5) + 24000L) * 10000; list[i++].e = 1; /* Check number */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -