Commit 41480af2 authored by Dan Williams's avatar Dan Williams Committed by Jeff Garzik

[PATCH] wireless/airo: WEXT and quality corrections

This patch brings the airo driver into line with the current
WEXT specification of signal quality.  It also fixes the values
used to determine signal quality and level for MPI & PCMCIA 350
cards.  It turns out that BSSListRid.rssi was actually in dBm
for 350 series cards, and that we can use the normalized
signal strength reported by the card as our "quality" value, on
a scale of 0 - 100.  Since signal level values are in dBm for
this driver, max_qual->level MUST be 0, as specified in the WEXT
spec.  This patch also uses the IW_QUAL constants new in WEXT
version 17.
Signed-off-by: default avatarDan Williams <dcbw@redhat.com>
parent 88d7bd8c
...@@ -754,7 +754,7 @@ typedef struct { ...@@ -754,7 +754,7 @@ typedef struct {
u8 zero; u8 zero;
u8 ssidLen; u8 ssidLen;
u8 ssid[32]; u8 ssid[32];
u16 rssi; u16 dBm;
#define CAP_ESS (1<<0) #define CAP_ESS (1<<0)
#define CAP_IBSS (1<<1) #define CAP_IBSS (1<<1)
#define CAP_PRIVACY (1<<4) #define CAP_PRIVACY (1<<4)
...@@ -1125,6 +1125,9 @@ static int micsetup(struct airo_info *ai); ...@@ -1125,6 +1125,9 @@ static int micsetup(struct airo_info *ai);
static int encapsulate(struct airo_info *ai, etherHead *pPacket, MICBuffer *buffer, int len); static int encapsulate(struct airo_info *ai, etherHead *pPacket, MICBuffer *buffer, int len);
static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *pPacket, u16 payLen); static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *pPacket, u16 payLen);
static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi);
static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm);
#include <linux/crypto.h> #include <linux/crypto.h>
#endif #endif
...@@ -1713,6 +1716,7 @@ static int readBSSListRid(struct airo_info *ai, int first, ...@@ -1713,6 +1716,7 @@ static int readBSSListRid(struct airo_info *ai, int first,
list->fh.dwell = le16_to_cpu(list->fh.dwell); list->fh.dwell = le16_to_cpu(list->fh.dwell);
list->dsChannel = le16_to_cpu(list->dsChannel); list->dsChannel = le16_to_cpu(list->dsChannel);
list->atimWindow = le16_to_cpu(list->atimWindow); list->atimWindow = le16_to_cpu(list->atimWindow);
list->dBm = le16_to_cpu(list->dBm);
return rc; return rc;
} }
...@@ -3245,7 +3249,10 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) ...@@ -3245,7 +3249,10 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
wstats.level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm; wstats.level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm;
else else
wstats.level = (hdr.rssi[1] + 321) / 2; wstats.level = (hdr.rssi[1] + 321) / 2;
wstats.updated = 3; wstats.noise = apriv->wstats.qual.noise;
wstats.updated = IW_QUAL_LEVEL_UPDATED
| IW_QUAL_QUAL_UPDATED
| IW_QUAL_NOISE_UPDATED;
/* Update spy records */ /* Update spy records */
wireless_spy_update(dev, sa, &wstats); wireless_spy_update(dev, sa, &wstats);
} }
...@@ -3588,7 +3595,10 @@ void mpi_receive_802_11 (struct airo_info *ai) ...@@ -3588,7 +3595,10 @@ void mpi_receive_802_11 (struct airo_info *ai)
wstats.level = 0x100 - ai->rssi[hdr.rssi[1]].rssidBm; wstats.level = 0x100 - ai->rssi[hdr.rssi[1]].rssidBm;
else else
wstats.level = (hdr.rssi[1] + 321) / 2; wstats.level = (hdr.rssi[1] + 321) / 2;
wstats.updated = 3; wstats.noise = ai->wstats.qual.noise;
wstats.updated = IW_QUAL_QUAL_UPDATED
| IW_QUAL_LEVEL_UPDATED
| IW_QUAL_NOISE_UPDATED;
/* Update spy records */ /* Update spy records */
wireless_spy_update(ai->dev, sa, &wstats); wireless_spy_update(ai->dev, sa, &wstats);
} }
...@@ -3679,7 +3689,7 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) ...@@ -3679,7 +3689,7 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
status = PC4500_readrid(ai,RID_RSSI,&rssi_rid,sizeof(rssi_rid),lock); status = PC4500_readrid(ai,RID_RSSI,&rssi_rid,sizeof(rssi_rid),lock);
if ( status == SUCCESS ) { if ( status == SUCCESS ) {
if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL) if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL)
memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512); memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512); /* Skip RID length member */
} }
else { else {
if (ai->rssi) { if (ai->rssi) {
...@@ -5348,7 +5358,7 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) { ...@@ -5348,7 +5358,7 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) {
(int)BSSList_rid.bssid[5], (int)BSSList_rid.bssid[5],
(int)BSSList_rid.ssidLen, (int)BSSList_rid.ssidLen,
BSSList_rid.ssid, BSSList_rid.ssid,
(int)BSSList_rid.rssi); (int)BSSList_rid.dBm);
ptr += sprintf(ptr, " channel = %d %s %s %s %s\n", ptr += sprintf(ptr, " channel = %d %s %s %s %s\n",
(int)BSSList_rid.dsChannel, (int)BSSList_rid.dsChannel,
BSSList_rid.cap & CAP_ESS ? "ESS" : "", BSSList_rid.cap & CAP_ESS ? "ESS" : "",
...@@ -5593,6 +5603,29 @@ static void __exit airo_cleanup_module( void ) ...@@ -5593,6 +5603,29 @@ static void __exit airo_cleanup_module( void )
* would not work at all... - Jean II * would not work at all... - Jean II
*/ */
static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi)
{
if( !rssi_rid )
return 0;
return (0x100 - rssi_rid[rssi].rssidBm);
}
static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm)
{
int i;
if( !rssi_rid )
return 0;
for( i = 0; i < 256; i++ )
if (rssi_rid[i].rssidBm == dbm)
return rssi_rid[i].rssipct;
return 0;
}
static int airo_get_quality (StatusRid *status_rid, CapabilityRid *cap_rid) static int airo_get_quality (StatusRid *status_rid, CapabilityRid *cap_rid)
{ {
int quality = 0; int quality = 0;
...@@ -6443,11 +6476,29 @@ static int airo_get_range(struct net_device *dev, ...@@ -6443,11 +6476,29 @@ static int airo_get_range(struct net_device *dev,
} }
range->num_frequency = k; range->num_frequency = k;
range->sensitivity = 65535;
/* Hum... Should put the right values there */ /* Hum... Should put the right values there */
if (local->rssi)
range->max_qual.qual = 100; /* % */
else
range->max_qual.qual = airo_get_max_quality(&cap_rid); range->max_qual.qual = airo_get_max_quality(&cap_rid);
range->max_qual.level = 0x100 - 120; /* -120 dBm */ range->max_qual.level = 0; /* 0 means we use dBm */
range->max_qual.noise = 0; range->max_qual.noise = 0;
range->sensitivity = 65535; range->max_qual.updated = 0;
/* Experimental measurements - boundary 11/5.5 Mb/s */
/* Note : with or without the (local->rssi), results
* are somewhat different. - Jean II */
if (local->rssi) {
range->avg_qual.qual = 50; /* % */
range->avg_qual.level = 186; /* -70 dBm */
} else {
range->avg_qual.qual = airo_get_avg_quality(&cap_rid);
range->avg_qual.level = 176; /* -80 dBm */
}
range->avg_qual.noise = 0;
range->avg_qual.updated = 0;
for(i = 0 ; i < 8 ; i++) { for(i = 0 ; i < 8 ; i++) {
range->bitrate[i] = cap_rid.supportedRates[i] * 500000; range->bitrate[i] = cap_rid.supportedRates[i] * 500000;
...@@ -6508,15 +6559,6 @@ static int airo_get_range(struct net_device *dev, ...@@ -6508,15 +6559,6 @@ static int airo_get_range(struct net_device *dev,
range->max_retry = 65535; range->max_retry = 65535;
range->min_r_time = 1024; range->min_r_time = 1024;
range->max_r_time = 65535 * 1024; range->max_r_time = 65535 * 1024;
/* Experimental measurements - boundary 11/5.5 Mb/s */
/* Note : with or without the (local->rssi), results
* are somewhat different. - Jean II */
range->avg_qual.qual = airo_get_avg_quality(&cap_rid);
if (local->rssi)
range->avg_qual.level = 186; /* -70 dBm */
else
range->avg_qual.level = 176; /* -80 dBm */
range->avg_qual.noise = 0;
/* Event capability (kernel + driver) */ /* Event capability (kernel + driver) */
range->event_capa[0] = (IW_EVENT_CAPA_K_0 | range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
...@@ -6676,12 +6718,18 @@ static int airo_get_aplist(struct net_device *dev, ...@@ -6676,12 +6718,18 @@ static int airo_get_aplist(struct net_device *dev,
loseSync = 0; loseSync = 0;
memcpy(address[i].sa_data, BSSList.bssid, ETH_ALEN); memcpy(address[i].sa_data, BSSList.bssid, ETH_ALEN);
address[i].sa_family = ARPHRD_ETHER; address[i].sa_family = ARPHRD_ETHER;
if (local->rssi) if (local->rssi) {
qual[i].level = 0x100 - local->rssi[BSSList.rssi].rssidBm; qual[i].level = 0x100 - BSSList.dBm;
else qual[i].qual = airo_dbm_to_pct( local->rssi, BSSList.dBm );
qual[i].level = (BSSList.rssi + 321) / 2; qual[i].updated = IW_QUAL_QUAL_UPDATED;
qual[i].qual = qual[i].noise = 0; } else {
qual[i].updated = 2; qual[i].level = (BSSList.dBm + 321) / 2;
qual[i].qual = 0;
qual[i].updated = IW_QUAL_QUAL_INVALID;
}
qual[i].noise = local->wstats.qual.noise;
qual[i].updated = IW_QUAL_LEVEL_UPDATED
| IW_QUAL_NOISE_UPDATED;
if (BSSList.index == 0xffff) if (BSSList.index == 0xffff)
break; break;
} }
...@@ -6760,7 +6808,7 @@ static int airo_set_scan(struct net_device *dev, ...@@ -6760,7 +6808,7 @@ static int airo_set_scan(struct net_device *dev,
static inline char *airo_translate_scan(struct net_device *dev, static inline char *airo_translate_scan(struct net_device *dev,
char *current_ev, char *current_ev,
char *end_buf, char *end_buf,
BSSListRid *list) BSSListRid *bss)
{ {
struct airo_info *ai = dev->priv; struct airo_info *ai = dev->priv;
struct iw_event iwe; /* Temporary buffer */ struct iw_event iwe; /* Temporary buffer */
...@@ -6771,22 +6819,22 @@ static inline char *airo_translate_scan(struct net_device *dev, ...@@ -6771,22 +6819,22 @@ static inline char *airo_translate_scan(struct net_device *dev,
/* First entry *MUST* be the AP MAC address */ /* First entry *MUST* be the AP MAC address */
iwe.cmd = SIOCGIWAP; iwe.cmd = SIOCGIWAP;
iwe.u.ap_addr.sa_family = ARPHRD_ETHER; iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
memcpy(iwe.u.ap_addr.sa_data, list->bssid, ETH_ALEN); memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
/* Other entries will be displayed in the order we give them */ /* Other entries will be displayed in the order we give them */
/* Add the ESSID */ /* Add the ESSID */
iwe.u.data.length = list->ssidLen; iwe.u.data.length = bss->ssidLen;
if(iwe.u.data.length > 32) if(iwe.u.data.length > 32)
iwe.u.data.length = 32; iwe.u.data.length = 32;
iwe.cmd = SIOCGIWESSID; iwe.cmd = SIOCGIWESSID;
iwe.u.data.flags = 1; iwe.u.data.flags = 1;
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, list->ssid); current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->ssid);
/* Add mode */ /* Add mode */
iwe.cmd = SIOCGIWMODE; iwe.cmd = SIOCGIWMODE;
capabilities = le16_to_cpu(list->cap); capabilities = le16_to_cpu(bss->cap);
if(capabilities & (CAP_ESS | CAP_IBSS)) { if(capabilities & (CAP_ESS | CAP_IBSS)) {
if(capabilities & CAP_ESS) if(capabilities & CAP_ESS)
iwe.u.mode = IW_MODE_MASTER; iwe.u.mode = IW_MODE_MASTER;
...@@ -6797,19 +6845,25 @@ static inline char *airo_translate_scan(struct net_device *dev, ...@@ -6797,19 +6845,25 @@ static inline char *airo_translate_scan(struct net_device *dev,
/* Add frequency */ /* Add frequency */
iwe.cmd = SIOCGIWFREQ; iwe.cmd = SIOCGIWFREQ;
iwe.u.freq.m = le16_to_cpu(list->dsChannel); iwe.u.freq.m = le16_to_cpu(bss->dsChannel);
iwe.u.freq.m = frequency_list[iwe.u.freq.m] * 100000; iwe.u.freq.m = frequency_list[iwe.u.freq.m] * 100000;
iwe.u.freq.e = 1; iwe.u.freq.e = 1;
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
/* Add quality statistics */ /* Add quality statistics */
iwe.cmd = IWEVQUAL; iwe.cmd = IWEVQUAL;
if (ai->rssi) if (ai->rssi) {
iwe.u.qual.level = 0x100 - ai->rssi[list->rssi].rssidBm; iwe.u.qual.level = 0x100 - bss->dBm;
else iwe.u.qual.qual = airo_dbm_to_pct( ai->rssi, bss->dBm );
iwe.u.qual.level = (list->rssi + 321) / 2; iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED;
iwe.u.qual.noise = 0; } else {
iwe.u.qual.level = (bss->dBm + 321) / 2;
iwe.u.qual.qual = 0; iwe.u.qual.qual = 0;
iwe.u.qual.updated = IW_QUAL_QUAL_INVALID;
}
iwe.u.qual.noise = ai->wstats.qual.noise;
iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED
| IW_QUAL_NOISE_UPDATED;
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
/* Add encryption capability */ /* Add encryption capability */
...@@ -6819,7 +6873,7 @@ static inline char *airo_translate_scan(struct net_device *dev, ...@@ -6819,7 +6873,7 @@ static inline char *airo_translate_scan(struct net_device *dev,
else else
iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.flags = IW_ENCODE_DISABLED;
iwe.u.data.length = 0; iwe.u.data.length = 0;
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, list->ssid); current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->ssid);
/* Rate : stuffing multiple values in a single event require a bit /* Rate : stuffing multiple values in a single event require a bit
* more of magic - Jean II */ * more of magic - Jean II */
...@@ -6831,10 +6885,10 @@ static inline char *airo_translate_scan(struct net_device *dev, ...@@ -6831,10 +6885,10 @@ static inline char *airo_translate_scan(struct net_device *dev,
/* Max 8 values */ /* Max 8 values */
for(i = 0 ; i < 8 ; i++) { for(i = 0 ; i < 8 ; i++) {
/* NULL terminated */ /* NULL terminated */
if(list->rates[i] == 0) if(bss->rates[i] == 0)
break; break;
/* Bit rate given in 500 kb/s units (+ 0x80) */ /* Bit rate given in 500 kb/s units (+ 0x80) */
iwe.u.bitrate.value = ((list->rates[i] & 0x7f) * 500000); iwe.u.bitrate.value = ((bss->rates[i] & 0x7f) * 500000);
/* Add new value to event */ /* Add new value to event */
current_val = iwe_stream_add_value(current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN); current_val = iwe_stream_add_value(current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN);
} }
...@@ -7153,18 +7207,22 @@ static void airo_read_wireless_stats(struct airo_info *local) ...@@ -7153,18 +7207,22 @@ static void airo_read_wireless_stats(struct airo_info *local)
/* The status */ /* The status */
local->wstats.status = status_rid.mode; local->wstats.status = status_rid.mode;
/* Signal quality and co. But where is the noise level ??? */ /* Signal quality and co */
local->wstats.qual.qual = airo_get_quality(&status_rid, &cap_rid); if (local->rssi) {
if (local->rssi) local->wstats.qual.level = airo_rssi_to_dbm( local->rssi, status_rid.sigQuality );
local->wstats.qual.level = 0x100 - local->rssi[status_rid.sigQuality].rssidBm; /* normalizedSignalStrength appears to be a percentage */
else local->wstats.qual.qual = status_rid.normalizedSignalStrength;
} else {
local->wstats.qual.level = (status_rid.normalizedSignalStrength + 321) / 2; local->wstats.qual.level = (status_rid.normalizedSignalStrength + 321) / 2;
local->wstats.qual.qual = airo_get_quality(&status_rid, &cap_rid);
}
local->wstats.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED;
if (status_rid.len >= 124) { if (status_rid.len >= 124) {
local->wstats.qual.noise = 256 - status_rid.noisedBm; local->wstats.qual.noise = 0x100 - status_rid.noisedBm;
local->wstats.qual.updated = 7; local->wstats.qual.updated |= IW_QUAL_NOISE_UPDATED;
} else { } else {
local->wstats.qual.noise = 0; local->wstats.qual.noise = 0;
local->wstats.qual.updated = 3; local->wstats.qual.updated |= IW_QUAL_NOISE_INVALID;
} }
/* Packets discarded in the wireless adapter due to wireless /* Packets discarded in the wireless adapter due to wireless
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment