aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorChristian Lamparter <chunkeey@web.de>2008-08-23 16:15:25 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-08-29 16:24:08 -0400
commit154e3af17fdce617605b63f3534dac2c10c90922 (patch)
tree48331503716ff5a5f1848237017d06c808f80a18 /drivers
parenta3ec233c90f0b8a5c00bf182f2c3ea9119b46caa (diff)
p54: fix rssi auto calibration
Ever wondered why the signal was so bad with p54 compared to madwifi, or intel? Well, if you have revision 1 rssi calibration curve points in your EEPROM, then wonder no more. The firmware wants a extra 1 byte padding for every curve point. But someone forgot to put them into the EEPROM's data structure... So now, big question: what happens when we blindly "memcpy" these data points? Signed-off-by: Christian Lamparter <chunkeey@web.de> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/p54/p54common.c140
-rw-r--r--drivers/net/wireless/p54/p54common.h23
2 files changed, 111 insertions, 52 deletions
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
index 29be3dc8ee09..4a6b5363ea4b 100644
--- a/drivers/net/wireless/p54/p54common.c
+++ b/drivers/net/wireless/p54/p54common.c
@@ -155,14 +155,14 @@ void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
155} 155}
156EXPORT_SYMBOL_GPL(p54_parse_firmware); 156EXPORT_SYMBOL_GPL(p54_parse_firmware);
157 157
158static int p54_convert_rev0_to_rev1(struct ieee80211_hw *dev, 158static int p54_convert_rev0(struct ieee80211_hw *dev,
159 struct pda_pa_curve_data *curve_data) 159 struct pda_pa_curve_data *curve_data)
160{ 160{
161 struct p54_common *priv = dev->priv; 161 struct p54_common *priv = dev->priv;
162 struct pda_pa_curve_data_sample_rev1 *rev1; 162 struct p54_pa_curve_data_sample *dst;
163 struct pda_pa_curve_data_sample_rev0 *rev0; 163 struct pda_pa_curve_data_sample_rev0 *src;
164 size_t cd_len = sizeof(*curve_data) + 164 size_t cd_len = sizeof(*curve_data) +
165 (curve_data->points_per_channel*sizeof(*rev1) + 2) * 165 (curve_data->points_per_channel*sizeof(*dst) + 2) *
166 curve_data->channels; 166 curve_data->channels;
167 unsigned int i, j; 167 unsigned int i, j;
168 void *source, *target; 168 void *source, *target;
@@ -180,27 +180,63 @@ static int p54_convert_rev0_to_rev1(struct ieee80211_hw *dev,
180 *((__le16 *)target) = *freq; 180 *((__le16 *)target) = *freq;
181 target += sizeof(__le16); 181 target += sizeof(__le16);
182 for (j = 0; j < curve_data->points_per_channel; j++) { 182 for (j = 0; j < curve_data->points_per_channel; j++) {
183 rev1 = target; 183 dst = target;
184 rev0 = source; 184 src = source;
185 185
186 rev1->rf_power = rev0->rf_power; 186 dst->rf_power = src->rf_power;
187 rev1->pa_detector = rev0->pa_detector; 187 dst->pa_detector = src->pa_detector;
188 rev1->data_64qam = rev0->pcv; 188 dst->data_64qam = src->pcv;
189 /* "invent" the points for the other modulations */ 189 /* "invent" the points for the other modulations */
190#define SUB(x,y) (u8)((x) - (y)) > (x) ? 0 : (x) - (y) 190#define SUB(x,y) (u8)((x) - (y)) > (x) ? 0 : (x) - (y)
191 rev1->data_16qam = SUB(rev0->pcv, 12); 191 dst->data_16qam = SUB(src->pcv, 12);
192 rev1->data_qpsk = SUB(rev1->data_16qam, 12); 192 dst->data_qpsk = SUB(dst->data_16qam, 12);
193 rev1->data_bpsk = SUB(rev1->data_qpsk, 12); 193 dst->data_bpsk = SUB(dst->data_qpsk, 12);
194 rev1->data_barker= SUB(rev1->data_bpsk, 14); 194 dst->data_barker = SUB(dst->data_bpsk, 14);
195#undef SUB 195#undef SUB
196 target += sizeof(*rev1); 196 target += sizeof(*dst);
197 source += sizeof(*rev0); 197 source += sizeof(*src);
198 } 198 }
199 } 199 }
200 200
201 return 0; 201 return 0;
202} 202}
203 203
204static int p54_convert_rev1(struct ieee80211_hw *dev,
205 struct pda_pa_curve_data *curve_data)
206{
207 struct p54_common *priv = dev->priv;
208 struct p54_pa_curve_data_sample *dst;
209 struct pda_pa_curve_data_sample_rev1 *src;
210 size_t cd_len = sizeof(*curve_data) +
211 (curve_data->points_per_channel*sizeof(*dst) + 2) *
212 curve_data->channels;
213 unsigned int i, j;
214 void *source, *target;
215
216 priv->curve_data = kmalloc(cd_len, GFP_KERNEL);
217 if (!priv->curve_data)
218 return -ENOMEM;
219
220 memcpy(priv->curve_data, curve_data, sizeof(*curve_data));
221 source = curve_data->data;
222 target = priv->curve_data->data;
223 for (i = 0; i < curve_data->channels; i++) {
224 __le16 *freq = source;
225 source += sizeof(__le16);
226 *((__le16 *)target) = *freq;
227 target += sizeof(__le16);
228 for (j = 0; j < curve_data->points_per_channel; j++) {
229 memcpy(target, source, sizeof(*src));
230
231 target += sizeof(*dst);
232 source += sizeof(*src);
233 }
234 source++;
235 }
236
237 return 0;
238}
239
204int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) 240int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
205{ 241{
206 struct p54_common *priv = dev->priv; 242 struct p54_common *priv = dev->priv;
@@ -250,27 +286,32 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
250 entry->data[1]*sizeof(*priv->output_limit)); 286 entry->data[1]*sizeof(*priv->output_limit));
251 priv->output_limit_len = entry->data[1]; 287 priv->output_limit_len = entry->data[1];
252 break; 288 break;
253 case PDR_PRISM_PA_CAL_CURVE_DATA: 289 case PDR_PRISM_PA_CAL_CURVE_DATA: {
254 if (data_len < sizeof(struct pda_pa_curve_data)) { 290 struct pda_pa_curve_data *curve_data =
291 (struct pda_pa_curve_data *)entry->data;
292 if (data_len < sizeof(*curve_data)) {
255 err = -EINVAL; 293 err = -EINVAL;
256 goto err; 294 goto err;
257 } 295 }
258 296
259 if (((struct pda_pa_curve_data *)entry->data)->cal_method_rev) { 297 switch (curve_data->cal_method_rev) {
260 priv->curve_data = kmalloc(data_len, GFP_KERNEL); 298 case 0:
261 if (!priv->curve_data) { 299 err = p54_convert_rev0(dev, curve_data);
262 err = -ENOMEM; 300 break;
263 goto err; 301 case 1:
264 } 302 err = p54_convert_rev1(dev, curve_data);
265 303 break;
266 memcpy(priv->curve_data, entry->data, data_len); 304 default:
267 } else { 305 printk(KERN_ERR "p54: unknown curve data "
268 err = p54_convert_rev0_to_rev1(dev, (struct pda_pa_curve_data *)entry->data); 306 "revision %d\n",
269 if (err) 307 curve_data->cal_method_rev);
270 goto err; 308 err = -ENODEV;
309 break;
271 } 310 }
311 if (err)
312 goto err;
272 313
273 break; 314 }
274 case PDR_PRISM_ZIF_TX_IQ_CALIBRATION: 315 case PDR_PRISM_ZIF_TX_IQ_CALIBRATION:
275 priv->iq_autocal = kmalloc(data_len, GFP_KERNEL); 316 priv->iq_autocal = kmalloc(data_len, GFP_KERNEL);
276 if (!priv->iq_autocal) { 317 if (!priv->iq_autocal) {
@@ -672,12 +713,9 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq)
672 struct p54_control_hdr *hdr; 713 struct p54_control_hdr *hdr;
673 struct p54_tx_control_channel *chan; 714 struct p54_tx_control_channel *chan;
674 unsigned int i; 715 unsigned int i;
675 size_t payload_len = sizeof(*chan) + sizeof(u32)*2 +
676 sizeof(*chan->curve_data) *
677 priv->curve_data->points_per_channel;
678 void *entry; 716 void *entry;
679 717
680 hdr = kzalloc(sizeof(*hdr) + payload_len + 718 hdr = kzalloc(sizeof(*hdr) + sizeof(*chan) +
681 priv->tx_hdr_len, GFP_KERNEL); 719 priv->tx_hdr_len, GFP_KERNEL);
682 if (!hdr) 720 if (!hdr)
683 return -ENOMEM; 721 return -ENOMEM;
@@ -689,10 +727,10 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq)
689 hdr->magic1 = cpu_to_le16(0x8001); 727 hdr->magic1 = cpu_to_le16(0x8001);
690 hdr->len = cpu_to_le16(sizeof(*chan)); 728 hdr->len = cpu_to_le16(sizeof(*chan));
691 hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE); 729 hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE);
692 p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + payload_len); 730 p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*chan));
693 731
694 chan->magic1 = cpu_to_le16(0x1); 732 chan->flags = cpu_to_le16(0x1);
695 chan->magic2 = cpu_to_le16(0x0); 733 chan->dwell = cpu_to_le16(0x0);
696 734
697 for (i = 0; i < priv->iq_autocal_len; i++) { 735 for (i = 0; i < priv->iq_autocal_len; i++) {
698 if (priv->iq_autocal[i].freq != freq) 736 if (priv->iq_autocal[i].freq != freq)
@@ -710,35 +748,41 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq)
710 continue; 748 continue;
711 749
712 chan->val_barker = 0x38; 750 chan->val_barker = 0x38;
713 chan->val_bpsk = priv->output_limit[i].val_bpsk; 751 chan->val_bpsk = chan->dup_bpsk =
714 chan->val_qpsk = priv->output_limit[i].val_qpsk; 752 priv->output_limit[i].val_bpsk;
715 chan->val_16qam = priv->output_limit[i].val_16qam; 753 chan->val_qpsk = chan->dup_qpsk =
716 chan->val_64qam = priv->output_limit[i].val_64qam; 754 priv->output_limit[i].val_qpsk;
755 chan->val_16qam = chan->dup_16qam =
756 priv->output_limit[i].val_16qam;
757 chan->val_64qam = chan->dup_64qam =
758 priv->output_limit[i].val_64qam;
717 break; 759 break;
718 } 760 }
719 if (i == priv->output_limit_len) 761 if (i == priv->output_limit_len)
720 goto err; 762 goto err;
721 763
722 chan->pa_points_per_curve = priv->curve_data->points_per_channel;
723
724 entry = priv->curve_data->data; 764 entry = priv->curve_data->data;
725 for (i = 0; i < priv->curve_data->channels; i++) { 765 for (i = 0; i < priv->curve_data->channels; i++) {
726 if (*((__le16 *)entry) != freq) { 766 if (*((__le16 *)entry) != freq) {
727 entry += sizeof(__le16); 767 entry += sizeof(__le16);
728 entry += sizeof(struct pda_pa_curve_data_sample_rev1) * 768 entry += sizeof(struct p54_pa_curve_data_sample) *
729 chan->pa_points_per_curve; 769 priv->curve_data->points_per_channel;
730 continue; 770 continue;
731 } 771 }
732 772
733 entry += sizeof(__le16); 773 entry += sizeof(__le16);
774 chan->pa_points_per_curve =
775 min(priv->curve_data->points_per_channel, (u8) 8);
776
734 memcpy(chan->curve_data, entry, sizeof(*chan->curve_data) * 777 memcpy(chan->curve_data, entry, sizeof(*chan->curve_data) *
735 chan->pa_points_per_curve); 778 chan->pa_points_per_curve);
736 break; 779 break;
737 } 780 }
738 781
739 memcpy(hdr->data + payload_len - 4, &chan->val_bpsk, 4); 782 chan->rssical_mul = cpu_to_le16(130);
783 chan->rssical_add = cpu_to_le16(0xfe70); /* -400 */
740 784
741 priv->tx(dev, hdr, sizeof(*hdr) + payload_len, 1); 785 priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*chan), 1);
742 return 0; 786 return 0;
743 787
744 err: 788 err:
diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h
index 9bc2a1cf4b57..a79c1a146917 100644
--- a/drivers/net/wireless/p54/p54common.h
+++ b/drivers/net/wireless/p54/p54common.h
@@ -89,6 +89,16 @@ struct pda_pa_curve_data_sample_rev1 {
89 u8 data_qpsk; 89 u8 data_qpsk;
90 u8 data_16qam; 90 u8 data_16qam;
91 u8 data_64qam; 91 u8 data_64qam;
92} __attribute__ ((packed));
93
94struct p54_pa_curve_data_sample {
95 u8 rf_power;
96 u8 pa_detector;
97 u8 data_barker;
98 u8 data_bpsk;
99 u8 data_qpsk;
100 u8 data_16qam;
101 u8 data_64qam;
92 u8 padding; 102 u8 padding;
93} __attribute__ ((packed)); 103} __attribute__ ((packed));
94 104
@@ -212,8 +222,8 @@ struct p54_tx_control_filter {
212} __attribute__ ((packed)); 222} __attribute__ ((packed));
213 223
214struct p54_tx_control_channel { 224struct p54_tx_control_channel {
215 __le16 magic1; 225 __le16 flags;
216 __le16 magic2; 226 __le16 dwell;
217 u8 padding1[20]; 227 u8 padding1[20];
218 struct pda_iq_autocal_entry iq_autocal; 228 struct pda_iq_autocal_entry iq_autocal;
219 u8 pa_points_per_curve; 229 u8 pa_points_per_curve;
@@ -222,8 +232,13 @@ struct p54_tx_control_channel {
222 u8 val_qpsk; 232 u8 val_qpsk;
223 u8 val_16qam; 233 u8 val_16qam;
224 u8 val_64qam; 234 u8 val_64qam;
225 struct pda_pa_curve_data_sample_rev1 curve_data[0]; 235 struct pda_pa_curve_data_sample_rev1 curve_data[8];
226 /* additional padding/data after curve_data */ 236 u8 dup_bpsk;
237 u8 dup_qpsk;
238 u8 dup_16qam;
239 u8 dup_64qam;
240 __le16 rssical_mul;
241 __le16 rssical_add;
227} __attribute__ ((packed)); 242} __attribute__ ((packed));
228 243
229struct p54_tx_control_led { 244struct p54_tx_control_led {