p54: parse output power table

For the upcoming tpc changes, the driver needs
to provide sensible max output values for each
supported channel.

And while the eeprom always had a output_limit
table, which defines the upper limit for each
frequency and modulation, it was never really
useful for anything... until now.

Note: For anyone wondering about what your card
is calibrated for: check "iw list".
	* 2412 MHz [1] (18.0 dBm)
	* 2437 MHz [6] (19.0 dBm)
	[...]
	* 5180 MHz [36] (18.0 dBm)
	* 5260 MHz [52] (17.0 dBm) (radar detection)
	* 5680 MHz [136] (19.0 dBm) (radar detection)
(for a Dell Wireless 1450 USB Adapter)

Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Christian Lamparter 2012-07-28 02:57:51 +02:00 committed by John W. Linville
parent 57f784fed3
commit 9bc63816be
2 changed files with 91 additions and 23 deletions

View file

@ -76,6 +76,7 @@ struct p54_channel_entry {
u16 freq;
u16 data;
int index;
int max_power;
enum ieee80211_band band;
};
@ -173,6 +174,7 @@ static int p54_generate_band(struct ieee80211_hw *dev,
for (i = 0, j = 0; (j < list->band_channel_num[band]) &&
(i < list->entries); i++) {
struct p54_channel_entry *chan = &list->channels[i];
struct ieee80211_channel *dest = &tmp->channels[j];
if (chan->band != band)
continue;
@ -190,14 +192,15 @@ static int p54_generate_band(struct ieee80211_hw *dev,
continue;
}
tmp->channels[j].band = chan->band;
tmp->channels[j].center_freq = chan->freq;
dest->band = chan->band;
dest->center_freq = chan->freq;
dest->max_power = chan->max_power;
priv->survey[*chan_num].channel = &tmp->channels[j];
priv->survey[*chan_num].filled = SURVEY_INFO_NOISE_DBM |
SURVEY_INFO_CHANNEL_TIME |
SURVEY_INFO_CHANNEL_TIME_BUSY |
SURVEY_INFO_CHANNEL_TIME_TX;
tmp->channels[j].hw_value = (*chan_num);
dest->hw_value = (*chan_num);
j++;
(*chan_num)++;
}
@ -229,10 +232,11 @@ static int p54_generate_band(struct ieee80211_hw *dev,
return ret;
}
static void p54_update_channel_param(struct p54_channel_list *list,
u16 freq, u16 data)
static struct p54_channel_entry *p54_update_channel_param(struct p54_channel_list *list,
u16 freq, u16 data)
{
int band, i;
int i;
struct p54_channel_entry *entry = NULL;
/*
* usually all lists in the eeprom are mostly sorted.
@ -241,30 +245,74 @@ static void p54_update_channel_param(struct p54_channel_list *list,
*/
for (i = list->entries; i >= 0; i--) {
if (freq == list->channels[i].freq) {
list->channels[i].data |= data;
entry = &list->channels[i];
break;
}
}
if ((i < 0) && (list->entries < list->max_entries)) {
/* entry does not exist yet. Initialize a new one. */
band = p54_get_band_from_freq(freq);
int band = p54_get_band_from_freq(freq);
/*
* filter out frequencies which don't belong into
* any supported band.
*/
if (band < 0)
return ;
if (band >= 0) {
i = list->entries++;
list->band_channel_num[band]++;
i = list->entries++;
list->band_channel_num[band]++;
entry = &list->channels[i];
entry->freq = freq;
entry->band = band;
entry->index = ieee80211_frequency_to_channel(freq);
entry->max_power = 0;
entry->data = 0;
}
}
list->channels[i].freq = freq;
list->channels[i].data = data;
list->channels[i].band = band;
list->channels[i].index = ieee80211_frequency_to_channel(freq);
/* TODO: parse output_limit and fill max_power */
if (entry)
entry->data |= data;
return entry;
}
static int p54_get_maxpower(struct p54_common *priv, void *data)
{
switch (priv->rxhw & PDR_SYNTH_FRONTEND_MASK) {
case PDR_SYNTH_FRONTEND_LONGBOW: {
struct pda_channel_output_limit_longbow *pda = data;
int j;
u16 rawpower = 0;
pda = data;
for (j = 0; j < ARRAY_SIZE(pda->point); j++) {
struct pda_channel_output_limit_point_longbow *point =
&pda->point[j];
rawpower = max(rawpower, le16_to_cpu(point->val_qpsk));
rawpower = max(rawpower, le16_to_cpu(point->val_bpsk));
rawpower = max(rawpower, le16_to_cpu(point->val_16qam));
rawpower = max(rawpower, le16_to_cpu(point->val_64qam));
}
/* longbow seems to use 1/16 dBm units */
return rawpower / 16;
}
case PDR_SYNTH_FRONTEND_DUETTE3:
case PDR_SYNTH_FRONTEND_DUETTE2:
case PDR_SYNTH_FRONTEND_FRISBEE:
case PDR_SYNTH_FRONTEND_XBOW: {
struct pda_channel_output_limit *pda = data;
u8 rawpower = 0;
rawpower = max(rawpower, pda->val_qpsk);
rawpower = max(rawpower, pda->val_bpsk);
rawpower = max(rawpower, pda->val_16qam);
rawpower = max(rawpower, pda->val_64qam);
/* raw values are in 1/4 dBm units */
return rawpower / 4;
}
default:
return 20;
}
}
@ -315,12 +363,19 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev)
}
if (i < priv->output_limit->entries) {
freq = le16_to_cpup((__le16 *) (i *
priv->output_limit->entry_size +
priv->output_limit->offset +
priv->output_limit->data));
struct p54_channel_entry *tmp;
p54_update_channel_param(list, freq, CHAN_HAS_LIMIT);
void *data = (void *) ((unsigned long) i *
priv->output_limit->entry_size +
priv->output_limit->offset +
priv->output_limit->data);
freq = le16_to_cpup((__le16 *) data);
tmp = p54_update_channel_param(list, freq,
CHAN_HAS_LIMIT);
if (tmp) {
tmp->max_power = p54_get_maxpower(priv, data);
}
}
if (i < priv->curve_data->entries) {
@ -834,11 +889,12 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
goto err;
}
priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
err = p54_generate_channel_lists(dev);
if (err)
goto err;
priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW)
p54_init_xbow_synth(priv);
if (!(synth & PDR_SYNTH_24_GHZ_DISABLED))

View file

@ -57,6 +57,18 @@ struct pda_channel_output_limit {
u8 rate_set_size;
} __packed;
struct pda_channel_output_limit_point_longbow {
__le16 val_bpsk;
__le16 val_qpsk;
__le16 val_16qam;
__le16 val_64qam;
} __packed;
struct pda_channel_output_limit_longbow {
__le16 freq;
struct pda_channel_output_limit_point_longbow point[3];
} __packed;
struct pda_pa_curve_data_sample_rev0 {
u8 rf_power;
u8 pa_detector;