Commit 9bc63816 authored by Christian Lamparter's avatar Christian Lamparter Committed by John W. Linville

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: default avatarChristian Lamparter <chunkeey@googlemail.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 57f784fe
...@@ -76,6 +76,7 @@ struct p54_channel_entry { ...@@ -76,6 +76,7 @@ struct p54_channel_entry {
u16 freq; u16 freq;
u16 data; u16 data;
int index; int index;
int max_power;
enum ieee80211_band band; enum ieee80211_band band;
}; };
...@@ -173,6 +174,7 @@ static int p54_generate_band(struct ieee80211_hw *dev, ...@@ -173,6 +174,7 @@ static int p54_generate_band(struct ieee80211_hw *dev,
for (i = 0, j = 0; (j < list->band_channel_num[band]) && for (i = 0, j = 0; (j < list->band_channel_num[band]) &&
(i < list->entries); i++) { (i < list->entries); i++) {
struct p54_channel_entry *chan = &list->channels[i]; struct p54_channel_entry *chan = &list->channels[i];
struct ieee80211_channel *dest = &tmp->channels[j];
if (chan->band != band) if (chan->band != band)
continue; continue;
...@@ -190,14 +192,15 @@ static int p54_generate_band(struct ieee80211_hw *dev, ...@@ -190,14 +192,15 @@ static int p54_generate_band(struct ieee80211_hw *dev,
continue; continue;
} }
tmp->channels[j].band = chan->band; dest->band = chan->band;
tmp->channels[j].center_freq = chan->freq; dest->center_freq = chan->freq;
dest->max_power = chan->max_power;
priv->survey[*chan_num].channel = &tmp->channels[j]; priv->survey[*chan_num].channel = &tmp->channels[j];
priv->survey[*chan_num].filled = SURVEY_INFO_NOISE_DBM | priv->survey[*chan_num].filled = SURVEY_INFO_NOISE_DBM |
SURVEY_INFO_CHANNEL_TIME | SURVEY_INFO_CHANNEL_TIME |
SURVEY_INFO_CHANNEL_TIME_BUSY | SURVEY_INFO_CHANNEL_TIME_BUSY |
SURVEY_INFO_CHANNEL_TIME_TX; SURVEY_INFO_CHANNEL_TIME_TX;
tmp->channels[j].hw_value = (*chan_num); dest->hw_value = (*chan_num);
j++; j++;
(*chan_num)++; (*chan_num)++;
} }
...@@ -229,10 +232,11 @@ static int p54_generate_band(struct ieee80211_hw *dev, ...@@ -229,10 +232,11 @@ static int p54_generate_band(struct ieee80211_hw *dev,
return ret; return ret;
} }
static void p54_update_channel_param(struct p54_channel_list *list, static struct p54_channel_entry *p54_update_channel_param(struct p54_channel_list *list,
u16 freq, u16 data) u16 freq, u16 data)
{ {
int band, i; int i;
struct p54_channel_entry *entry = NULL;
/* /*
* usually all lists in the eeprom are mostly sorted. * usually all lists in the eeprom are mostly sorted.
...@@ -241,30 +245,74 @@ static void p54_update_channel_param(struct p54_channel_list *list, ...@@ -241,30 +245,74 @@ static void p54_update_channel_param(struct p54_channel_list *list,
*/ */
for (i = list->entries; i >= 0; i--) { for (i = list->entries; i >= 0; i--) {
if (freq == list->channels[i].freq) { if (freq == list->channels[i].freq) {
list->channels[i].data |= data; entry = &list->channels[i];
break; break;
} }
} }
if ((i < 0) && (list->entries < list->max_entries)) { if ((i < 0) && (list->entries < list->max_entries)) {
/* entry does not exist yet. Initialize a new one. */ /* 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 * filter out frequencies which don't belong into
* any supported band. * any supported band.
*/ */
if (band < 0) if (band >= 0) {
return ; 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;
}
}
i = list->entries++; if (entry)
list->band_channel_num[band]++; entry->data |= data;
list->channels[i].freq = freq; return entry;
list->channels[i].data = data; }
list->channels[i].band = band;
list->channels[i].index = ieee80211_frequency_to_channel(freq); static int p54_get_maxpower(struct p54_common *priv, void *data)
/* TODO: parse output_limit and fill max_power */ {
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) ...@@ -315,12 +363,19 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev)
} }
if (i < priv->output_limit->entries) { if (i < priv->output_limit->entries) {
freq = le16_to_cpup((__le16 *) (i * struct p54_channel_entry *tmp;
priv->output_limit->entry_size +
priv->output_limit->offset + void *data = (void *) ((unsigned long) i *
priv->output_limit->data)); priv->output_limit->entry_size +
priv->output_limit->offset +
p54_update_channel_param(list, freq, CHAN_HAS_LIMIT); 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) { if (i < priv->curve_data->entries) {
...@@ -834,11 +889,12 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) ...@@ -834,11 +889,12 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
goto err; goto err;
} }
priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
err = p54_generate_channel_lists(dev); err = p54_generate_channel_lists(dev);
if (err) if (err)
goto err; goto err;
priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW) if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW)
p54_init_xbow_synth(priv); p54_init_xbow_synth(priv);
if (!(synth & PDR_SYNTH_24_GHZ_DISABLED)) if (!(synth & PDR_SYNTH_24_GHZ_DISABLED))
......
...@@ -57,6 +57,18 @@ struct pda_channel_output_limit { ...@@ -57,6 +57,18 @@ struct pda_channel_output_limit {
u8 rate_set_size; u8 rate_set_size;
} __packed; } __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 { struct pda_pa_curve_data_sample_rev0 {
u8 rf_power; u8 rf_power;
u8 pa_detector; u8 pa_detector;
......
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