xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/intersil/p54/eeprom.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * EEPROM parser code for mac80211 Prism54 drivers
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
6*4882a593Smuzhiyun  * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
7*4882a593Smuzhiyun  * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * Based on:
10*4882a593Smuzhiyun  * - the islsm (softmac prism54) driver, which is:
11*4882a593Smuzhiyun  *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
12*4882a593Smuzhiyun  * - stlc45xx driver
13*4882a593Smuzhiyun  *   Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
14*4882a593Smuzhiyun  */
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include <linux/firmware.h>
17*4882a593Smuzhiyun #include <linux/etherdevice.h>
18*4882a593Smuzhiyun #include <linux/sort.h>
19*4882a593Smuzhiyun #include <linux/slab.h>
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun #include <net/mac80211.h>
22*4882a593Smuzhiyun #include <linux/crc-ccitt.h>
23*4882a593Smuzhiyun #include <linux/export.h>
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #include "p54.h"
26*4882a593Smuzhiyun #include "eeprom.h"
27*4882a593Smuzhiyun #include "lmac.h"
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun static struct ieee80211_rate p54_bgrates[] = {
30*4882a593Smuzhiyun 	{ .bitrate = 10, .hw_value = 0, },
31*4882a593Smuzhiyun 	{ .bitrate = 20, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
32*4882a593Smuzhiyun 	{ .bitrate = 55, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
33*4882a593Smuzhiyun 	{ .bitrate = 110, .hw_value = 3, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
34*4882a593Smuzhiyun 	{ .bitrate = 60, .hw_value = 4, },
35*4882a593Smuzhiyun 	{ .bitrate = 90, .hw_value = 5, },
36*4882a593Smuzhiyun 	{ .bitrate = 120, .hw_value = 6, },
37*4882a593Smuzhiyun 	{ .bitrate = 180, .hw_value = 7, },
38*4882a593Smuzhiyun 	{ .bitrate = 240, .hw_value = 8, },
39*4882a593Smuzhiyun 	{ .bitrate = 360, .hw_value = 9, },
40*4882a593Smuzhiyun 	{ .bitrate = 480, .hw_value = 10, },
41*4882a593Smuzhiyun 	{ .bitrate = 540, .hw_value = 11, },
42*4882a593Smuzhiyun };
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun static struct ieee80211_rate p54_arates[] = {
45*4882a593Smuzhiyun 	{ .bitrate = 60, .hw_value = 4, },
46*4882a593Smuzhiyun 	{ .bitrate = 90, .hw_value = 5, },
47*4882a593Smuzhiyun 	{ .bitrate = 120, .hw_value = 6, },
48*4882a593Smuzhiyun 	{ .bitrate = 180, .hw_value = 7, },
49*4882a593Smuzhiyun 	{ .bitrate = 240, .hw_value = 8, },
50*4882a593Smuzhiyun 	{ .bitrate = 360, .hw_value = 9, },
51*4882a593Smuzhiyun 	{ .bitrate = 480, .hw_value = 10, },
52*4882a593Smuzhiyun 	{ .bitrate = 540, .hw_value = 11, },
53*4882a593Smuzhiyun };
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun static struct p54_rssi_db_entry p54_rssi_default = {
56*4882a593Smuzhiyun 	/*
57*4882a593Smuzhiyun 	 * The defaults are taken from usb-logs of the
58*4882a593Smuzhiyun 	 * vendor driver. So, they should be safe to
59*4882a593Smuzhiyun 	 * use in case we can't get a match from the
60*4882a593Smuzhiyun 	 * rssi <-> dBm conversion database.
61*4882a593Smuzhiyun 	 */
62*4882a593Smuzhiyun 	.mul = 130,
63*4882a593Smuzhiyun 	.add = -398,
64*4882a593Smuzhiyun };
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun #define CHAN_HAS_CAL		BIT(0)
67*4882a593Smuzhiyun #define CHAN_HAS_LIMIT		BIT(1)
68*4882a593Smuzhiyun #define CHAN_HAS_CURVE		BIT(2)
69*4882a593Smuzhiyun #define CHAN_HAS_ALL		(CHAN_HAS_CAL | CHAN_HAS_LIMIT | CHAN_HAS_CURVE)
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun struct p54_channel_entry {
72*4882a593Smuzhiyun 	u16 freq;
73*4882a593Smuzhiyun 	u16 data;
74*4882a593Smuzhiyun 	int index;
75*4882a593Smuzhiyun 	int max_power;
76*4882a593Smuzhiyun 	enum nl80211_band band;
77*4882a593Smuzhiyun };
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun struct p54_channel_list {
80*4882a593Smuzhiyun 	struct p54_channel_entry *channels;
81*4882a593Smuzhiyun 	size_t entries;
82*4882a593Smuzhiyun 	size_t max_entries;
83*4882a593Smuzhiyun 	size_t band_channel_num[NUM_NL80211_BANDS];
84*4882a593Smuzhiyun };
85*4882a593Smuzhiyun 
p54_get_band_from_freq(u16 freq)86*4882a593Smuzhiyun static int p54_get_band_from_freq(u16 freq)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun 	/* FIXME: sync these values with the 802.11 spec */
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	if ((freq >= 2412) && (freq <= 2484))
91*4882a593Smuzhiyun 		return NL80211_BAND_2GHZ;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	if ((freq >= 4920) && (freq <= 5825))
94*4882a593Smuzhiyun 		return NL80211_BAND_5GHZ;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	return -1;
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun 
same_band(u16 freq,u16 freq2)99*4882a593Smuzhiyun static int same_band(u16 freq, u16 freq2)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun 	return p54_get_band_from_freq(freq) == p54_get_band_from_freq(freq2);
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun 
p54_compare_channels(const void * _a,const void * _b)104*4882a593Smuzhiyun static int p54_compare_channels(const void *_a,
105*4882a593Smuzhiyun 				const void *_b)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun 	const struct p54_channel_entry *a = _a;
108*4882a593Smuzhiyun 	const struct p54_channel_entry *b = _b;
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	return a->freq - b->freq;
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun 
p54_compare_rssichan(const void * _a,const void * _b)113*4882a593Smuzhiyun static int p54_compare_rssichan(const void *_a,
114*4882a593Smuzhiyun 				const void *_b)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun 	const struct p54_rssi_db_entry *a = _a;
117*4882a593Smuzhiyun 	const struct p54_rssi_db_entry *b = _b;
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	return a->freq - b->freq;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun 
p54_fill_band_bitrates(struct ieee80211_hw * dev,struct ieee80211_supported_band * band_entry,enum nl80211_band band)122*4882a593Smuzhiyun static int p54_fill_band_bitrates(struct ieee80211_hw *dev,
123*4882a593Smuzhiyun 				  struct ieee80211_supported_band *band_entry,
124*4882a593Smuzhiyun 				  enum nl80211_band band)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun 	/* TODO: generate rate array dynamically */
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	switch (band) {
129*4882a593Smuzhiyun 	case NL80211_BAND_2GHZ:
130*4882a593Smuzhiyun 		band_entry->bitrates = p54_bgrates;
131*4882a593Smuzhiyun 		band_entry->n_bitrates = ARRAY_SIZE(p54_bgrates);
132*4882a593Smuzhiyun 		break;
133*4882a593Smuzhiyun 	case NL80211_BAND_5GHZ:
134*4882a593Smuzhiyun 		band_entry->bitrates = p54_arates;
135*4882a593Smuzhiyun 		band_entry->n_bitrates = ARRAY_SIZE(p54_arates);
136*4882a593Smuzhiyun 		break;
137*4882a593Smuzhiyun 	default:
138*4882a593Smuzhiyun 		return -EINVAL;
139*4882a593Smuzhiyun 	}
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	return 0;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun 
p54_generate_band(struct ieee80211_hw * dev,struct p54_channel_list * list,unsigned int * chan_num,enum nl80211_band band)144*4882a593Smuzhiyun static int p54_generate_band(struct ieee80211_hw *dev,
145*4882a593Smuzhiyun 			     struct p54_channel_list *list,
146*4882a593Smuzhiyun 			     unsigned int *chan_num,
147*4882a593Smuzhiyun 			     enum nl80211_band band)
148*4882a593Smuzhiyun {
149*4882a593Smuzhiyun 	struct p54_common *priv = dev->priv;
150*4882a593Smuzhiyun 	struct ieee80211_supported_band *tmp, *old;
151*4882a593Smuzhiyun 	unsigned int i, j;
152*4882a593Smuzhiyun 	int ret = -ENOMEM;
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	if ((!list->entries) || (!list->band_channel_num[band]))
155*4882a593Smuzhiyun 		return -EINVAL;
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
158*4882a593Smuzhiyun 	if (!tmp)
159*4882a593Smuzhiyun 		goto err_out;
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	tmp->channels = kcalloc(list->band_channel_num[band],
162*4882a593Smuzhiyun 				sizeof(struct ieee80211_channel),
163*4882a593Smuzhiyun 				GFP_KERNEL);
164*4882a593Smuzhiyun 	if (!tmp->channels)
165*4882a593Smuzhiyun 		goto err_out;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	ret = p54_fill_band_bitrates(dev, tmp, band);
168*4882a593Smuzhiyun 	if (ret)
169*4882a593Smuzhiyun 		goto err_out;
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	for (i = 0, j = 0; (j < list->band_channel_num[band]) &&
172*4882a593Smuzhiyun 			   (i < list->entries); i++) {
173*4882a593Smuzhiyun 		struct p54_channel_entry *chan = &list->channels[i];
174*4882a593Smuzhiyun 		struct ieee80211_channel *dest = &tmp->channels[j];
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 		if (chan->band != band)
177*4882a593Smuzhiyun 			continue;
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 		if (chan->data != CHAN_HAS_ALL) {
180*4882a593Smuzhiyun 			wiphy_err(dev->wiphy, "%s%s%s is/are missing for "
181*4882a593Smuzhiyun 				  "channel:%d [%d MHz].\n",
182*4882a593Smuzhiyun 				  (chan->data & CHAN_HAS_CAL ? "" :
183*4882a593Smuzhiyun 				   " [iqauto calibration data]"),
184*4882a593Smuzhiyun 				  (chan->data & CHAN_HAS_LIMIT ? "" :
185*4882a593Smuzhiyun 				   " [output power limits]"),
186*4882a593Smuzhiyun 				  (chan->data & CHAN_HAS_CURVE ? "" :
187*4882a593Smuzhiyun 				   " [curve data]"),
188*4882a593Smuzhiyun 				  chan->index, chan->freq);
189*4882a593Smuzhiyun 			continue;
190*4882a593Smuzhiyun 		}
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 		dest->band = chan->band;
193*4882a593Smuzhiyun 		dest->center_freq = chan->freq;
194*4882a593Smuzhiyun 		dest->max_power = chan->max_power;
195*4882a593Smuzhiyun 		priv->survey[*chan_num].channel = &tmp->channels[j];
196*4882a593Smuzhiyun 		priv->survey[*chan_num].filled = SURVEY_INFO_NOISE_DBM |
197*4882a593Smuzhiyun 			SURVEY_INFO_TIME |
198*4882a593Smuzhiyun 			SURVEY_INFO_TIME_BUSY |
199*4882a593Smuzhiyun 			SURVEY_INFO_TIME_TX;
200*4882a593Smuzhiyun 		dest->hw_value = (*chan_num);
201*4882a593Smuzhiyun 		j++;
202*4882a593Smuzhiyun 		(*chan_num)++;
203*4882a593Smuzhiyun 	}
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	if (j == 0) {
206*4882a593Smuzhiyun 		wiphy_err(dev->wiphy, "Disabling totally damaged %d GHz band\n",
207*4882a593Smuzhiyun 			  (band == NL80211_BAND_2GHZ) ? 2 : 5);
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 		ret = -ENODATA;
210*4882a593Smuzhiyun 		goto err_out;
211*4882a593Smuzhiyun 	}
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	tmp->n_channels = j;
214*4882a593Smuzhiyun 	old = priv->band_table[band];
215*4882a593Smuzhiyun 	priv->band_table[band] = tmp;
216*4882a593Smuzhiyun 	if (old) {
217*4882a593Smuzhiyun 		kfree(old->channels);
218*4882a593Smuzhiyun 		kfree(old);
219*4882a593Smuzhiyun 	}
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	return 0;
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun err_out:
224*4882a593Smuzhiyun 	if (tmp) {
225*4882a593Smuzhiyun 		kfree(tmp->channels);
226*4882a593Smuzhiyun 		kfree(tmp);
227*4882a593Smuzhiyun 	}
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	return ret;
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun 
p54_update_channel_param(struct p54_channel_list * list,u16 freq,u16 data)232*4882a593Smuzhiyun static struct p54_channel_entry *p54_update_channel_param(struct p54_channel_list *list,
233*4882a593Smuzhiyun 							  u16 freq, u16 data)
234*4882a593Smuzhiyun {
235*4882a593Smuzhiyun 	int i;
236*4882a593Smuzhiyun 	struct p54_channel_entry *entry = NULL;
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	/*
239*4882a593Smuzhiyun 	 * usually all lists in the eeprom are mostly sorted.
240*4882a593Smuzhiyun 	 * so it's very likely that the entry we are looking for
241*4882a593Smuzhiyun 	 * is right at the end of the list
242*4882a593Smuzhiyun 	 */
243*4882a593Smuzhiyun 	for (i = list->entries; i >= 0; i--) {
244*4882a593Smuzhiyun 		if (freq == list->channels[i].freq) {
245*4882a593Smuzhiyun 			entry = &list->channels[i];
246*4882a593Smuzhiyun 			break;
247*4882a593Smuzhiyun 		}
248*4882a593Smuzhiyun 	}
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 	if ((i < 0) && (list->entries < list->max_entries)) {
251*4882a593Smuzhiyun 		/* entry does not exist yet. Initialize a new one. */
252*4882a593Smuzhiyun 		int band = p54_get_band_from_freq(freq);
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 		/*
255*4882a593Smuzhiyun 		 * filter out frequencies which don't belong into
256*4882a593Smuzhiyun 		 * any supported band.
257*4882a593Smuzhiyun 		 */
258*4882a593Smuzhiyun 		if (band >= 0) {
259*4882a593Smuzhiyun 			i = list->entries++;
260*4882a593Smuzhiyun 			list->band_channel_num[band]++;
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 			entry = &list->channels[i];
263*4882a593Smuzhiyun 			entry->freq = freq;
264*4882a593Smuzhiyun 			entry->band = band;
265*4882a593Smuzhiyun 			entry->index = ieee80211_frequency_to_channel(freq);
266*4882a593Smuzhiyun 			entry->max_power = 0;
267*4882a593Smuzhiyun 			entry->data = 0;
268*4882a593Smuzhiyun 		}
269*4882a593Smuzhiyun 	}
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	if (entry)
272*4882a593Smuzhiyun 		entry->data |= data;
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	return entry;
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun 
p54_get_maxpower(struct p54_common * priv,void * data)277*4882a593Smuzhiyun static int p54_get_maxpower(struct p54_common *priv, void *data)
278*4882a593Smuzhiyun {
279*4882a593Smuzhiyun 	switch (priv->rxhw & PDR_SYNTH_FRONTEND_MASK) {
280*4882a593Smuzhiyun 	case PDR_SYNTH_FRONTEND_LONGBOW: {
281*4882a593Smuzhiyun 		struct pda_channel_output_limit_longbow *pda = data;
282*4882a593Smuzhiyun 		int j;
283*4882a593Smuzhiyun 		u16 rawpower = 0;
284*4882a593Smuzhiyun 		pda = data;
285*4882a593Smuzhiyun 		for (j = 0; j < ARRAY_SIZE(pda->point); j++) {
286*4882a593Smuzhiyun 			struct pda_channel_output_limit_point_longbow *point =
287*4882a593Smuzhiyun 				&pda->point[j];
288*4882a593Smuzhiyun 			rawpower = max_t(u16,
289*4882a593Smuzhiyun 				rawpower, le16_to_cpu(point->val_qpsk));
290*4882a593Smuzhiyun 			rawpower = max_t(u16,
291*4882a593Smuzhiyun 				rawpower, le16_to_cpu(point->val_bpsk));
292*4882a593Smuzhiyun 			rawpower = max_t(u16,
293*4882a593Smuzhiyun 				rawpower, le16_to_cpu(point->val_16qam));
294*4882a593Smuzhiyun 			rawpower = max_t(u16,
295*4882a593Smuzhiyun 				rawpower, le16_to_cpu(point->val_64qam));
296*4882a593Smuzhiyun 		}
297*4882a593Smuzhiyun 		/* longbow seems to use 1/16 dBm units */
298*4882a593Smuzhiyun 		return rawpower / 16;
299*4882a593Smuzhiyun 		}
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	case PDR_SYNTH_FRONTEND_DUETTE3:
302*4882a593Smuzhiyun 	case PDR_SYNTH_FRONTEND_DUETTE2:
303*4882a593Smuzhiyun 	case PDR_SYNTH_FRONTEND_FRISBEE:
304*4882a593Smuzhiyun 	case PDR_SYNTH_FRONTEND_XBOW: {
305*4882a593Smuzhiyun 		struct pda_channel_output_limit *pda = data;
306*4882a593Smuzhiyun 		u8 rawpower = 0;
307*4882a593Smuzhiyun 		rawpower = max(rawpower, pda->val_qpsk);
308*4882a593Smuzhiyun 		rawpower = max(rawpower, pda->val_bpsk);
309*4882a593Smuzhiyun 		rawpower = max(rawpower, pda->val_16qam);
310*4882a593Smuzhiyun 		rawpower = max(rawpower, pda->val_64qam);
311*4882a593Smuzhiyun 		/* raw values are in 1/4 dBm units */
312*4882a593Smuzhiyun 		return rawpower / 4;
313*4882a593Smuzhiyun 		}
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	default:
316*4882a593Smuzhiyun 		return 20;
317*4882a593Smuzhiyun 	}
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun 
p54_generate_channel_lists(struct ieee80211_hw * dev)320*4882a593Smuzhiyun static int p54_generate_channel_lists(struct ieee80211_hw *dev)
321*4882a593Smuzhiyun {
322*4882a593Smuzhiyun 	struct p54_common *priv = dev->priv;
323*4882a593Smuzhiyun 	struct p54_channel_list *list;
324*4882a593Smuzhiyun 	unsigned int i, j, k, max_channel_num;
325*4882a593Smuzhiyun 	int ret = 0;
326*4882a593Smuzhiyun 	u16 freq;
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	if ((priv->iq_autocal_len != priv->curve_data->entries) ||
329*4882a593Smuzhiyun 	    (priv->iq_autocal_len != priv->output_limit->entries))
330*4882a593Smuzhiyun 		wiphy_err(dev->wiphy,
331*4882a593Smuzhiyun 			  "Unsupported or damaged EEPROM detected. "
332*4882a593Smuzhiyun 			  "You may not be able to use all channels.\n");
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	max_channel_num = max_t(unsigned int, priv->output_limit->entries,
335*4882a593Smuzhiyun 				priv->iq_autocal_len);
336*4882a593Smuzhiyun 	max_channel_num = max_t(unsigned int, max_channel_num,
337*4882a593Smuzhiyun 				priv->curve_data->entries);
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	list = kzalloc(sizeof(*list), GFP_KERNEL);
340*4882a593Smuzhiyun 	if (!list) {
341*4882a593Smuzhiyun 		ret = -ENOMEM;
342*4882a593Smuzhiyun 		goto free;
343*4882a593Smuzhiyun 	}
344*4882a593Smuzhiyun 	priv->chan_num = max_channel_num;
345*4882a593Smuzhiyun 	priv->survey = kcalloc(max_channel_num, sizeof(struct survey_info),
346*4882a593Smuzhiyun 			       GFP_KERNEL);
347*4882a593Smuzhiyun 	if (!priv->survey) {
348*4882a593Smuzhiyun 		ret = -ENOMEM;
349*4882a593Smuzhiyun 		goto free;
350*4882a593Smuzhiyun 	}
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun 	list->max_entries = max_channel_num;
353*4882a593Smuzhiyun 	list->channels = kcalloc(max_channel_num,
354*4882a593Smuzhiyun 				 sizeof(struct p54_channel_entry),
355*4882a593Smuzhiyun 				 GFP_KERNEL);
356*4882a593Smuzhiyun 	if (!list->channels) {
357*4882a593Smuzhiyun 		ret = -ENOMEM;
358*4882a593Smuzhiyun 		goto free;
359*4882a593Smuzhiyun 	}
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	for (i = 0; i < max_channel_num; i++) {
362*4882a593Smuzhiyun 		if (i < priv->iq_autocal_len) {
363*4882a593Smuzhiyun 			freq = le16_to_cpu(priv->iq_autocal[i].freq);
364*4882a593Smuzhiyun 			p54_update_channel_param(list, freq, CHAN_HAS_CAL);
365*4882a593Smuzhiyun 		}
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 		if (i < priv->output_limit->entries) {
368*4882a593Smuzhiyun 			struct p54_channel_entry *tmp;
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 			void *data = (void *) ((unsigned long) i *
371*4882a593Smuzhiyun 				priv->output_limit->entry_size +
372*4882a593Smuzhiyun 				priv->output_limit->offset +
373*4882a593Smuzhiyun 				priv->output_limit->data);
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 			freq = le16_to_cpup((__le16 *) data);
376*4882a593Smuzhiyun 			tmp = p54_update_channel_param(list, freq,
377*4882a593Smuzhiyun 						       CHAN_HAS_LIMIT);
378*4882a593Smuzhiyun 			if (tmp) {
379*4882a593Smuzhiyun 				tmp->max_power = p54_get_maxpower(priv, data);
380*4882a593Smuzhiyun 			}
381*4882a593Smuzhiyun 		}
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 		if (i < priv->curve_data->entries) {
384*4882a593Smuzhiyun 			freq = le16_to_cpup((__le16 *) (i *
385*4882a593Smuzhiyun 					    priv->curve_data->entry_size +
386*4882a593Smuzhiyun 					    priv->curve_data->offset +
387*4882a593Smuzhiyun 					    priv->curve_data->data));
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 			p54_update_channel_param(list, freq, CHAN_HAS_CURVE);
390*4882a593Smuzhiyun 		}
391*4882a593Smuzhiyun 	}
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	/* sort the channel list by frequency */
394*4882a593Smuzhiyun 	sort(list->channels, list->entries, sizeof(struct p54_channel_entry),
395*4882a593Smuzhiyun 	     p54_compare_channels, NULL);
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	k = 0;
398*4882a593Smuzhiyun 	for (i = 0, j = 0; i < NUM_NL80211_BANDS; i++) {
399*4882a593Smuzhiyun 		if (p54_generate_band(dev, list, &k, i) == 0)
400*4882a593Smuzhiyun 			j++;
401*4882a593Smuzhiyun 	}
402*4882a593Smuzhiyun 	if (j == 0) {
403*4882a593Smuzhiyun 		/* no useable band available. */
404*4882a593Smuzhiyun 		ret = -EINVAL;
405*4882a593Smuzhiyun 	}
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun free:
408*4882a593Smuzhiyun 	if (list) {
409*4882a593Smuzhiyun 		kfree(list->channels);
410*4882a593Smuzhiyun 		kfree(list);
411*4882a593Smuzhiyun 	}
412*4882a593Smuzhiyun 	if (ret) {
413*4882a593Smuzhiyun 		kfree(priv->survey);
414*4882a593Smuzhiyun 		priv->survey = NULL;
415*4882a593Smuzhiyun 	}
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 	return ret;
418*4882a593Smuzhiyun }
419*4882a593Smuzhiyun 
p54_convert_rev0(struct ieee80211_hw * dev,struct pda_pa_curve_data * curve_data)420*4882a593Smuzhiyun static int p54_convert_rev0(struct ieee80211_hw *dev,
421*4882a593Smuzhiyun 			    struct pda_pa_curve_data *curve_data)
422*4882a593Smuzhiyun {
423*4882a593Smuzhiyun 	struct p54_common *priv = dev->priv;
424*4882a593Smuzhiyun 	struct p54_pa_curve_data_sample *dst;
425*4882a593Smuzhiyun 	struct pda_pa_curve_data_sample_rev0 *src;
426*4882a593Smuzhiyun 	size_t cd_len = sizeof(*curve_data) +
427*4882a593Smuzhiyun 		(curve_data->points_per_channel*sizeof(*dst) + 2) *
428*4882a593Smuzhiyun 		 curve_data->channels;
429*4882a593Smuzhiyun 	unsigned int i, j;
430*4882a593Smuzhiyun 	void *source, *target;
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	priv->curve_data = kmalloc(sizeof(*priv->curve_data) + cd_len,
433*4882a593Smuzhiyun 				   GFP_KERNEL);
434*4882a593Smuzhiyun 	if (!priv->curve_data)
435*4882a593Smuzhiyun 		return -ENOMEM;
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	priv->curve_data->entries = curve_data->channels;
438*4882a593Smuzhiyun 	priv->curve_data->entry_size = sizeof(__le16) +
439*4882a593Smuzhiyun 		sizeof(*dst) * curve_data->points_per_channel;
440*4882a593Smuzhiyun 	priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
441*4882a593Smuzhiyun 	priv->curve_data->len = cd_len;
442*4882a593Smuzhiyun 	memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
443*4882a593Smuzhiyun 	source = curve_data->data;
444*4882a593Smuzhiyun 	target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
445*4882a593Smuzhiyun 	for (i = 0; i < curve_data->channels; i++) {
446*4882a593Smuzhiyun 		__le16 *freq = source;
447*4882a593Smuzhiyun 		source += sizeof(__le16);
448*4882a593Smuzhiyun 		*((__le16 *)target) = *freq;
449*4882a593Smuzhiyun 		target += sizeof(__le16);
450*4882a593Smuzhiyun 		for (j = 0; j < curve_data->points_per_channel; j++) {
451*4882a593Smuzhiyun 			dst = target;
452*4882a593Smuzhiyun 			src = source;
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 			dst->rf_power = src->rf_power;
455*4882a593Smuzhiyun 			dst->pa_detector = src->pa_detector;
456*4882a593Smuzhiyun 			dst->data_64qam = src->pcv;
457*4882a593Smuzhiyun 			/* "invent" the points for the other modulations */
458*4882a593Smuzhiyun #define SUB(x, y) (u8)(((x) - (y)) > (x) ? 0 : (x) - (y))
459*4882a593Smuzhiyun 			dst->data_16qam = SUB(src->pcv, 12);
460*4882a593Smuzhiyun 			dst->data_qpsk = SUB(dst->data_16qam, 12);
461*4882a593Smuzhiyun 			dst->data_bpsk = SUB(dst->data_qpsk, 12);
462*4882a593Smuzhiyun 			dst->data_barker = SUB(dst->data_bpsk, 14);
463*4882a593Smuzhiyun #undef SUB
464*4882a593Smuzhiyun 			target += sizeof(*dst);
465*4882a593Smuzhiyun 			source += sizeof(*src);
466*4882a593Smuzhiyun 		}
467*4882a593Smuzhiyun 	}
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 	return 0;
470*4882a593Smuzhiyun }
471*4882a593Smuzhiyun 
p54_convert_rev1(struct ieee80211_hw * dev,struct pda_pa_curve_data * curve_data)472*4882a593Smuzhiyun static int p54_convert_rev1(struct ieee80211_hw *dev,
473*4882a593Smuzhiyun 			    struct pda_pa_curve_data *curve_data)
474*4882a593Smuzhiyun {
475*4882a593Smuzhiyun 	struct p54_common *priv = dev->priv;
476*4882a593Smuzhiyun 	struct p54_pa_curve_data_sample *dst;
477*4882a593Smuzhiyun 	struct pda_pa_curve_data_sample_rev1 *src;
478*4882a593Smuzhiyun 	size_t cd_len = sizeof(*curve_data) +
479*4882a593Smuzhiyun 		(curve_data->points_per_channel*sizeof(*dst) + 2) *
480*4882a593Smuzhiyun 		 curve_data->channels;
481*4882a593Smuzhiyun 	unsigned int i, j;
482*4882a593Smuzhiyun 	void *source, *target;
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 	priv->curve_data = kzalloc(cd_len + sizeof(*priv->curve_data),
485*4882a593Smuzhiyun 				   GFP_KERNEL);
486*4882a593Smuzhiyun 	if (!priv->curve_data)
487*4882a593Smuzhiyun 		return -ENOMEM;
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	priv->curve_data->entries = curve_data->channels;
490*4882a593Smuzhiyun 	priv->curve_data->entry_size = sizeof(__le16) +
491*4882a593Smuzhiyun 		sizeof(*dst) * curve_data->points_per_channel;
492*4882a593Smuzhiyun 	priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
493*4882a593Smuzhiyun 	priv->curve_data->len = cd_len;
494*4882a593Smuzhiyun 	memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
495*4882a593Smuzhiyun 	source = curve_data->data;
496*4882a593Smuzhiyun 	target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
497*4882a593Smuzhiyun 	for (i = 0; i < curve_data->channels; i++) {
498*4882a593Smuzhiyun 		__le16 *freq = source;
499*4882a593Smuzhiyun 		source += sizeof(__le16);
500*4882a593Smuzhiyun 		*((__le16 *)target) = *freq;
501*4882a593Smuzhiyun 		target += sizeof(__le16);
502*4882a593Smuzhiyun 		for (j = 0; j < curve_data->points_per_channel; j++) {
503*4882a593Smuzhiyun 			memcpy(target, source, sizeof(*src));
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 			target += sizeof(*dst);
506*4882a593Smuzhiyun 			source += sizeof(*src);
507*4882a593Smuzhiyun 		}
508*4882a593Smuzhiyun 		source++;
509*4882a593Smuzhiyun 	}
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 	return 0;
512*4882a593Smuzhiyun }
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun static const char *p54_rf_chips[] = { "INVALID-0", "Duette3", "Duette2",
515*4882a593Smuzhiyun 	"Frisbee", "Xbow", "Longbow", "INVALID-6", "INVALID-7" };
516*4882a593Smuzhiyun 
p54_parse_rssical(struct ieee80211_hw * dev,u8 * data,int len,u16 type)517*4882a593Smuzhiyun static int p54_parse_rssical(struct ieee80211_hw *dev,
518*4882a593Smuzhiyun 			     u8 *data, int len, u16 type)
519*4882a593Smuzhiyun {
520*4882a593Smuzhiyun 	struct p54_common *priv = dev->priv;
521*4882a593Smuzhiyun 	struct p54_rssi_db_entry *entry;
522*4882a593Smuzhiyun 	size_t db_len, entries;
523*4882a593Smuzhiyun 	int offset = 0, i;
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 	if (type != PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) {
526*4882a593Smuzhiyun 		entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2;
527*4882a593Smuzhiyun 		if (len != sizeof(struct pda_rssi_cal_entry) * entries) {
528*4882a593Smuzhiyun 			wiphy_err(dev->wiphy, "rssical size mismatch.\n");
529*4882a593Smuzhiyun 			goto err_data;
530*4882a593Smuzhiyun 		}
531*4882a593Smuzhiyun 	} else {
532*4882a593Smuzhiyun 		/*
533*4882a593Smuzhiyun 		 * Some devices (Dell 1450 USB, Xbow 5GHz card, etc...)
534*4882a593Smuzhiyun 		 * have an empty two byte header.
535*4882a593Smuzhiyun 		 */
536*4882a593Smuzhiyun 		if (*((__le16 *)&data[offset]) == cpu_to_le16(0))
537*4882a593Smuzhiyun 			offset += 2;
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 		entries = (len - offset) /
540*4882a593Smuzhiyun 			sizeof(struct pda_rssi_cal_ext_entry);
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun 		if (len < offset ||
543*4882a593Smuzhiyun 		    (len - offset) % sizeof(struct pda_rssi_cal_ext_entry) ||
544*4882a593Smuzhiyun 		    entries == 0) {
545*4882a593Smuzhiyun 			wiphy_err(dev->wiphy, "invalid rssi database.\n");
546*4882a593Smuzhiyun 			goto err_data;
547*4882a593Smuzhiyun 		}
548*4882a593Smuzhiyun 	}
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun 	db_len = sizeof(*entry) * entries;
551*4882a593Smuzhiyun 	priv->rssi_db = kzalloc(db_len + sizeof(*priv->rssi_db), GFP_KERNEL);
552*4882a593Smuzhiyun 	if (!priv->rssi_db)
553*4882a593Smuzhiyun 		return -ENOMEM;
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 	priv->rssi_db->offset = 0;
556*4882a593Smuzhiyun 	priv->rssi_db->entries = entries;
557*4882a593Smuzhiyun 	priv->rssi_db->entry_size = sizeof(*entry);
558*4882a593Smuzhiyun 	priv->rssi_db->len = db_len;
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun 	entry = (void *)((unsigned long)priv->rssi_db->data + priv->rssi_db->offset);
561*4882a593Smuzhiyun 	if (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) {
562*4882a593Smuzhiyun 		struct pda_rssi_cal_ext_entry *cal = (void *) &data[offset];
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun 		for (i = 0; i < entries; i++) {
565*4882a593Smuzhiyun 			entry[i].freq = le16_to_cpu(cal[i].freq);
566*4882a593Smuzhiyun 			entry[i].mul = (s16) le16_to_cpu(cal[i].mul);
567*4882a593Smuzhiyun 			entry[i].add = (s16) le16_to_cpu(cal[i].add);
568*4882a593Smuzhiyun 		}
569*4882a593Smuzhiyun 	} else {
570*4882a593Smuzhiyun 		struct pda_rssi_cal_entry *cal = (void *) &data[offset];
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 		for (i = 0; i < entries; i++) {
573*4882a593Smuzhiyun 			u16 freq = 0;
574*4882a593Smuzhiyun 			switch (i) {
575*4882a593Smuzhiyun 			case NL80211_BAND_2GHZ:
576*4882a593Smuzhiyun 				freq = 2437;
577*4882a593Smuzhiyun 				break;
578*4882a593Smuzhiyun 			case NL80211_BAND_5GHZ:
579*4882a593Smuzhiyun 				freq = 5240;
580*4882a593Smuzhiyun 				break;
581*4882a593Smuzhiyun 			}
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 			entry[i].freq = freq;
584*4882a593Smuzhiyun 			entry[i].mul = (s16) le16_to_cpu(cal[i].mul);
585*4882a593Smuzhiyun 			entry[i].add = (s16) le16_to_cpu(cal[i].add);
586*4882a593Smuzhiyun 		}
587*4882a593Smuzhiyun 	}
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	/* sort the list by channel frequency */
590*4882a593Smuzhiyun 	sort(entry, entries, sizeof(*entry), p54_compare_rssichan, NULL);
591*4882a593Smuzhiyun 	return 0;
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun err_data:
594*4882a593Smuzhiyun 	wiphy_err(dev->wiphy,
595*4882a593Smuzhiyun 		  "rssi calibration data packing type:(%x) len:%d.\n",
596*4882a593Smuzhiyun 		  type, len);
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 	print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE, data, len);
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	wiphy_err(dev->wiphy, "please report this issue.\n");
601*4882a593Smuzhiyun 	return -EINVAL;
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun 
p54_rssi_find(struct p54_common * priv,const u16 freq)604*4882a593Smuzhiyun struct p54_rssi_db_entry *p54_rssi_find(struct p54_common *priv, const u16 freq)
605*4882a593Smuzhiyun {
606*4882a593Smuzhiyun 	struct p54_rssi_db_entry *entry;
607*4882a593Smuzhiyun 	int i, found = -1;
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun 	if (!priv->rssi_db)
610*4882a593Smuzhiyun 		return &p54_rssi_default;
611*4882a593Smuzhiyun 
612*4882a593Smuzhiyun 	entry = (void *)(priv->rssi_db->data + priv->rssi_db->offset);
613*4882a593Smuzhiyun 	for (i = 0; i < priv->rssi_db->entries; i++) {
614*4882a593Smuzhiyun 		if (!same_band(freq, entry[i].freq))
615*4882a593Smuzhiyun 			continue;
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun 		if (found == -1) {
618*4882a593Smuzhiyun 			found = i;
619*4882a593Smuzhiyun 			continue;
620*4882a593Smuzhiyun 		}
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun 		/* nearest match */
623*4882a593Smuzhiyun 		if (abs(freq - entry[i].freq) <
624*4882a593Smuzhiyun 		    abs(freq - entry[found].freq)) {
625*4882a593Smuzhiyun 			found = i;
626*4882a593Smuzhiyun 			continue;
627*4882a593Smuzhiyun 		} else {
628*4882a593Smuzhiyun 			break;
629*4882a593Smuzhiyun 		}
630*4882a593Smuzhiyun 	}
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun 	return found < 0 ? &p54_rssi_default : &entry[found];
633*4882a593Smuzhiyun }
634*4882a593Smuzhiyun 
p54_parse_default_country(struct ieee80211_hw * dev,void * data,int len)635*4882a593Smuzhiyun static void p54_parse_default_country(struct ieee80211_hw *dev,
636*4882a593Smuzhiyun 				      void *data, int len)
637*4882a593Smuzhiyun {
638*4882a593Smuzhiyun 	struct pda_country *country;
639*4882a593Smuzhiyun 
640*4882a593Smuzhiyun 	if (len != sizeof(*country)) {
641*4882a593Smuzhiyun 		wiphy_err(dev->wiphy,
642*4882a593Smuzhiyun 			  "found possible invalid default country eeprom entry. (entry size: %d)\n",
643*4882a593Smuzhiyun 			  len);
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun 		print_hex_dump_bytes("country:", DUMP_PREFIX_NONE,
646*4882a593Smuzhiyun 				     data, len);
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun 		wiphy_err(dev->wiphy, "please report this issue.\n");
649*4882a593Smuzhiyun 		return;
650*4882a593Smuzhiyun 	}
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun 	country = (struct pda_country *) data;
653*4882a593Smuzhiyun 	if (country->flags == PDR_COUNTRY_CERT_CODE_PSEUDO)
654*4882a593Smuzhiyun 		regulatory_hint(dev->wiphy, country->alpha2);
655*4882a593Smuzhiyun 	else {
656*4882a593Smuzhiyun 		/* TODO:
657*4882a593Smuzhiyun 		 * write a shared/common function that converts
658*4882a593Smuzhiyun 		 * "Regulatory domain codes" (802.11-2007 14.8.2.2)
659*4882a593Smuzhiyun 		 * into ISO/IEC 3166-1 alpha2 for regulatory_hint.
660*4882a593Smuzhiyun 		 */
661*4882a593Smuzhiyun 	}
662*4882a593Smuzhiyun }
663*4882a593Smuzhiyun 
p54_convert_output_limits(struct ieee80211_hw * dev,u8 * data,size_t len)664*4882a593Smuzhiyun static int p54_convert_output_limits(struct ieee80211_hw *dev,
665*4882a593Smuzhiyun 				     u8 *data, size_t len)
666*4882a593Smuzhiyun {
667*4882a593Smuzhiyun 	struct p54_common *priv = dev->priv;
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun 	if (len < 2)
670*4882a593Smuzhiyun 		return -EINVAL;
671*4882a593Smuzhiyun 
672*4882a593Smuzhiyun 	if (data[0] != 0) {
673*4882a593Smuzhiyun 		wiphy_err(dev->wiphy, "unknown output power db revision:%x\n",
674*4882a593Smuzhiyun 			  data[0]);
675*4882a593Smuzhiyun 		return -EINVAL;
676*4882a593Smuzhiyun 	}
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun 	if (2 + data[1] * sizeof(struct pda_channel_output_limit) > len)
679*4882a593Smuzhiyun 		return -EINVAL;
680*4882a593Smuzhiyun 
681*4882a593Smuzhiyun 	priv->output_limit = kmalloc(data[1] *
682*4882a593Smuzhiyun 		sizeof(struct pda_channel_output_limit) +
683*4882a593Smuzhiyun 		sizeof(*priv->output_limit), GFP_KERNEL);
684*4882a593Smuzhiyun 
685*4882a593Smuzhiyun 	if (!priv->output_limit)
686*4882a593Smuzhiyun 		return -ENOMEM;
687*4882a593Smuzhiyun 
688*4882a593Smuzhiyun 	priv->output_limit->offset = 0;
689*4882a593Smuzhiyun 	priv->output_limit->entries = data[1];
690*4882a593Smuzhiyun 	priv->output_limit->entry_size =
691*4882a593Smuzhiyun 		sizeof(struct pda_channel_output_limit);
692*4882a593Smuzhiyun 	priv->output_limit->len = priv->output_limit->entry_size *
693*4882a593Smuzhiyun 				  priv->output_limit->entries +
694*4882a593Smuzhiyun 				  priv->output_limit->offset;
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun 	memcpy(priv->output_limit->data, &data[2],
697*4882a593Smuzhiyun 	       data[1] * sizeof(struct pda_channel_output_limit));
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun 	return 0;
700*4882a593Smuzhiyun }
701*4882a593Smuzhiyun 
p54_convert_db(struct pda_custom_wrapper * src,size_t total_len)702*4882a593Smuzhiyun static struct p54_cal_database *p54_convert_db(struct pda_custom_wrapper *src,
703*4882a593Smuzhiyun 					       size_t total_len)
704*4882a593Smuzhiyun {
705*4882a593Smuzhiyun 	struct p54_cal_database *dst;
706*4882a593Smuzhiyun 	size_t payload_len, entries, entry_size, offset;
707*4882a593Smuzhiyun 
708*4882a593Smuzhiyun 	payload_len = le16_to_cpu(src->len);
709*4882a593Smuzhiyun 	entries = le16_to_cpu(src->entries);
710*4882a593Smuzhiyun 	entry_size = le16_to_cpu(src->entry_size);
711*4882a593Smuzhiyun 	offset = le16_to_cpu(src->offset);
712*4882a593Smuzhiyun 	if (((entries * entry_size + offset) != payload_len) ||
713*4882a593Smuzhiyun 	     (payload_len + sizeof(*src) != total_len))
714*4882a593Smuzhiyun 		return NULL;
715*4882a593Smuzhiyun 
716*4882a593Smuzhiyun 	dst = kmalloc(sizeof(*dst) + payload_len, GFP_KERNEL);
717*4882a593Smuzhiyun 	if (!dst)
718*4882a593Smuzhiyun 		return NULL;
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun 	dst->entries = entries;
721*4882a593Smuzhiyun 	dst->entry_size = entry_size;
722*4882a593Smuzhiyun 	dst->offset = offset;
723*4882a593Smuzhiyun 	dst->len = payload_len;
724*4882a593Smuzhiyun 
725*4882a593Smuzhiyun 	memcpy(dst->data, src->data, payload_len);
726*4882a593Smuzhiyun 	return dst;
727*4882a593Smuzhiyun }
728*4882a593Smuzhiyun 
p54_parse_eeprom(struct ieee80211_hw * dev,void * eeprom,int len)729*4882a593Smuzhiyun int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
730*4882a593Smuzhiyun {
731*4882a593Smuzhiyun 	struct p54_common *priv = dev->priv;
732*4882a593Smuzhiyun 	struct eeprom_pda_wrap *wrap;
733*4882a593Smuzhiyun 	struct pda_entry *entry;
734*4882a593Smuzhiyun 	unsigned int data_len, entry_len;
735*4882a593Smuzhiyun 	void *tmp;
736*4882a593Smuzhiyun 	int err;
737*4882a593Smuzhiyun 	u8 *end = (u8 *)eeprom + len;
738*4882a593Smuzhiyun 	u16 synth = 0;
739*4882a593Smuzhiyun 	u16 crc16 = ~0;
740*4882a593Smuzhiyun 
741*4882a593Smuzhiyun 	wrap = (struct eeprom_pda_wrap *) eeprom;
742*4882a593Smuzhiyun 	entry = (void *)wrap->data + le16_to_cpu(wrap->len);
743*4882a593Smuzhiyun 
744*4882a593Smuzhiyun 	/* verify that at least the entry length/code fits */
745*4882a593Smuzhiyun 	while ((u8 *)entry <= end - sizeof(*entry)) {
746*4882a593Smuzhiyun 		entry_len = le16_to_cpu(entry->len);
747*4882a593Smuzhiyun 		data_len = ((entry_len - 1) << 1);
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun 		/* abort if entry exceeds whole structure */
750*4882a593Smuzhiyun 		if ((u8 *)entry + sizeof(*entry) + data_len > end)
751*4882a593Smuzhiyun 			break;
752*4882a593Smuzhiyun 
753*4882a593Smuzhiyun 		switch (le16_to_cpu(entry->code)) {
754*4882a593Smuzhiyun 		case PDR_MAC_ADDRESS:
755*4882a593Smuzhiyun 			if (data_len != ETH_ALEN)
756*4882a593Smuzhiyun 				break;
757*4882a593Smuzhiyun 			SET_IEEE80211_PERM_ADDR(dev, entry->data);
758*4882a593Smuzhiyun 			break;
759*4882a593Smuzhiyun 		case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS:
760*4882a593Smuzhiyun 			if (priv->output_limit)
761*4882a593Smuzhiyun 				break;
762*4882a593Smuzhiyun 			err = p54_convert_output_limits(dev, entry->data,
763*4882a593Smuzhiyun 							data_len);
764*4882a593Smuzhiyun 			if (err)
765*4882a593Smuzhiyun 				goto err;
766*4882a593Smuzhiyun 			break;
767*4882a593Smuzhiyun 		case PDR_PRISM_PA_CAL_CURVE_DATA: {
768*4882a593Smuzhiyun 			struct pda_pa_curve_data *curve_data =
769*4882a593Smuzhiyun 				(struct pda_pa_curve_data *)entry->data;
770*4882a593Smuzhiyun 			if (data_len < sizeof(*curve_data)) {
771*4882a593Smuzhiyun 				err = -EINVAL;
772*4882a593Smuzhiyun 				goto err;
773*4882a593Smuzhiyun 			}
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 			switch (curve_data->cal_method_rev) {
776*4882a593Smuzhiyun 			case 0:
777*4882a593Smuzhiyun 				err = p54_convert_rev0(dev, curve_data);
778*4882a593Smuzhiyun 				break;
779*4882a593Smuzhiyun 			case 1:
780*4882a593Smuzhiyun 				err = p54_convert_rev1(dev, curve_data);
781*4882a593Smuzhiyun 				break;
782*4882a593Smuzhiyun 			default:
783*4882a593Smuzhiyun 				wiphy_err(dev->wiphy,
784*4882a593Smuzhiyun 					  "unknown curve data revision %d\n",
785*4882a593Smuzhiyun 					  curve_data->cal_method_rev);
786*4882a593Smuzhiyun 				err = -ENODEV;
787*4882a593Smuzhiyun 				break;
788*4882a593Smuzhiyun 			}
789*4882a593Smuzhiyun 			if (err)
790*4882a593Smuzhiyun 				goto err;
791*4882a593Smuzhiyun 			}
792*4882a593Smuzhiyun 			break;
793*4882a593Smuzhiyun 		case PDR_PRISM_ZIF_TX_IQ_CALIBRATION:
794*4882a593Smuzhiyun 			priv->iq_autocal = kmemdup(entry->data, data_len,
795*4882a593Smuzhiyun 						   GFP_KERNEL);
796*4882a593Smuzhiyun 			if (!priv->iq_autocal) {
797*4882a593Smuzhiyun 				err = -ENOMEM;
798*4882a593Smuzhiyun 				goto err;
799*4882a593Smuzhiyun 			}
800*4882a593Smuzhiyun 
801*4882a593Smuzhiyun 			priv->iq_autocal_len = data_len / sizeof(struct pda_iq_autocal_entry);
802*4882a593Smuzhiyun 			break;
803*4882a593Smuzhiyun 		case PDR_DEFAULT_COUNTRY:
804*4882a593Smuzhiyun 			p54_parse_default_country(dev, entry->data, data_len);
805*4882a593Smuzhiyun 			break;
806*4882a593Smuzhiyun 		case PDR_INTERFACE_LIST:
807*4882a593Smuzhiyun 			tmp = entry->data;
808*4882a593Smuzhiyun 			while ((u8 *)tmp < entry->data + data_len) {
809*4882a593Smuzhiyun 				struct exp_if *exp_if = tmp;
810*4882a593Smuzhiyun 				if (exp_if->if_id == cpu_to_le16(IF_ID_ISL39000))
811*4882a593Smuzhiyun 					synth = le16_to_cpu(exp_if->variant);
812*4882a593Smuzhiyun 				tmp += sizeof(*exp_if);
813*4882a593Smuzhiyun 			}
814*4882a593Smuzhiyun 			break;
815*4882a593Smuzhiyun 		case PDR_HARDWARE_PLATFORM_COMPONENT_ID:
816*4882a593Smuzhiyun 			if (data_len < 2)
817*4882a593Smuzhiyun 				break;
818*4882a593Smuzhiyun 			priv->version = *(u8 *)(entry->data + 1);
819*4882a593Smuzhiyun 			break;
820*4882a593Smuzhiyun 		case PDR_RSSI_LINEAR_APPROXIMATION:
821*4882a593Smuzhiyun 		case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND:
822*4882a593Smuzhiyun 		case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED:
823*4882a593Smuzhiyun 			err = p54_parse_rssical(dev, entry->data, data_len,
824*4882a593Smuzhiyun 						le16_to_cpu(entry->code));
825*4882a593Smuzhiyun 			if (err)
826*4882a593Smuzhiyun 				goto err;
827*4882a593Smuzhiyun 			break;
828*4882a593Smuzhiyun 		case PDR_RSSI_LINEAR_APPROXIMATION_CUSTOMV2: {
829*4882a593Smuzhiyun 			struct pda_custom_wrapper *pda = (void *) entry->data;
830*4882a593Smuzhiyun 			__le16 *src;
831*4882a593Smuzhiyun 			u16 *dst;
832*4882a593Smuzhiyun 			int i;
833*4882a593Smuzhiyun 
834*4882a593Smuzhiyun 			if (priv->rssi_db || data_len < sizeof(*pda))
835*4882a593Smuzhiyun 				break;
836*4882a593Smuzhiyun 
837*4882a593Smuzhiyun 			priv->rssi_db = p54_convert_db(pda, data_len);
838*4882a593Smuzhiyun 			if (!priv->rssi_db)
839*4882a593Smuzhiyun 				break;
840*4882a593Smuzhiyun 
841*4882a593Smuzhiyun 			src = (void *) priv->rssi_db->data;
842*4882a593Smuzhiyun 			dst = (void *) priv->rssi_db->data;
843*4882a593Smuzhiyun 
844*4882a593Smuzhiyun 			for (i = 0; i < priv->rssi_db->entries; i++)
845*4882a593Smuzhiyun 				*(dst++) = (s16) le16_to_cpu(*(src++));
846*4882a593Smuzhiyun 
847*4882a593Smuzhiyun 			}
848*4882a593Smuzhiyun 			break;
849*4882a593Smuzhiyun 		case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM: {
850*4882a593Smuzhiyun 			struct pda_custom_wrapper *pda = (void *) entry->data;
851*4882a593Smuzhiyun 			if (priv->output_limit || data_len < sizeof(*pda))
852*4882a593Smuzhiyun 				break;
853*4882a593Smuzhiyun 			priv->output_limit = p54_convert_db(pda, data_len);
854*4882a593Smuzhiyun 			}
855*4882a593Smuzhiyun 			break;
856*4882a593Smuzhiyun 		case PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM: {
857*4882a593Smuzhiyun 			struct pda_custom_wrapper *pda = (void *) entry->data;
858*4882a593Smuzhiyun 			if (priv->curve_data || data_len < sizeof(*pda))
859*4882a593Smuzhiyun 				break;
860*4882a593Smuzhiyun 			priv->curve_data = p54_convert_db(pda, data_len);
861*4882a593Smuzhiyun 			}
862*4882a593Smuzhiyun 			break;
863*4882a593Smuzhiyun 		case PDR_END:
864*4882a593Smuzhiyun 			crc16 = ~crc_ccitt(crc16, (u8 *) entry, sizeof(*entry));
865*4882a593Smuzhiyun 			if (crc16 != le16_to_cpup((__le16 *)entry->data)) {
866*4882a593Smuzhiyun 				wiphy_err(dev->wiphy, "eeprom failed checksum "
867*4882a593Smuzhiyun 					 "test!\n");
868*4882a593Smuzhiyun 				err = -ENOMSG;
869*4882a593Smuzhiyun 				goto err;
870*4882a593Smuzhiyun 			} else {
871*4882a593Smuzhiyun 				goto good_eeprom;
872*4882a593Smuzhiyun 			}
873*4882a593Smuzhiyun 			break;
874*4882a593Smuzhiyun 		default:
875*4882a593Smuzhiyun 			break;
876*4882a593Smuzhiyun 		}
877*4882a593Smuzhiyun 
878*4882a593Smuzhiyun 		crc16 = crc_ccitt(crc16, (u8 *)entry, (entry_len + 1) * 2);
879*4882a593Smuzhiyun 		entry = (void *)entry + (entry_len + 1) * 2;
880*4882a593Smuzhiyun 	}
881*4882a593Smuzhiyun 
882*4882a593Smuzhiyun 	wiphy_err(dev->wiphy, "unexpected end of eeprom data.\n");
883*4882a593Smuzhiyun 	err = -ENODATA;
884*4882a593Smuzhiyun 	goto err;
885*4882a593Smuzhiyun 
886*4882a593Smuzhiyun good_eeprom:
887*4882a593Smuzhiyun 	if (!synth || !priv->iq_autocal || !priv->output_limit ||
888*4882a593Smuzhiyun 	    !priv->curve_data) {
889*4882a593Smuzhiyun 		wiphy_err(dev->wiphy,
890*4882a593Smuzhiyun 			  "not all required entries found in eeprom!\n");
891*4882a593Smuzhiyun 		err = -EINVAL;
892*4882a593Smuzhiyun 		goto err;
893*4882a593Smuzhiyun 	}
894*4882a593Smuzhiyun 
895*4882a593Smuzhiyun 	priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
896*4882a593Smuzhiyun 
897*4882a593Smuzhiyun 	err = p54_generate_channel_lists(dev);
898*4882a593Smuzhiyun 	if (err)
899*4882a593Smuzhiyun 		goto err;
900*4882a593Smuzhiyun 
901*4882a593Smuzhiyun 	if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW)
902*4882a593Smuzhiyun 		p54_init_xbow_synth(priv);
903*4882a593Smuzhiyun 	if (!(synth & PDR_SYNTH_24_GHZ_DISABLED))
904*4882a593Smuzhiyun 		dev->wiphy->bands[NL80211_BAND_2GHZ] =
905*4882a593Smuzhiyun 			priv->band_table[NL80211_BAND_2GHZ];
906*4882a593Smuzhiyun 	if (!(synth & PDR_SYNTH_5_GHZ_DISABLED))
907*4882a593Smuzhiyun 		dev->wiphy->bands[NL80211_BAND_5GHZ] =
908*4882a593Smuzhiyun 			priv->band_table[NL80211_BAND_5GHZ];
909*4882a593Smuzhiyun 	if ((synth & PDR_SYNTH_RX_DIV_MASK) == PDR_SYNTH_RX_DIV_SUPPORTED)
910*4882a593Smuzhiyun 		priv->rx_diversity_mask = 3;
911*4882a593Smuzhiyun 	if ((synth & PDR_SYNTH_TX_DIV_MASK) == PDR_SYNTH_TX_DIV_SUPPORTED)
912*4882a593Smuzhiyun 		priv->tx_diversity_mask = 3;
913*4882a593Smuzhiyun 
914*4882a593Smuzhiyun 	if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
915*4882a593Smuzhiyun 		u8 perm_addr[ETH_ALEN];
916*4882a593Smuzhiyun 
917*4882a593Smuzhiyun 		wiphy_warn(dev->wiphy,
918*4882a593Smuzhiyun 			   "Invalid hwaddr! Using randomly generated MAC addr\n");
919*4882a593Smuzhiyun 		eth_random_addr(perm_addr);
920*4882a593Smuzhiyun 		SET_IEEE80211_PERM_ADDR(dev, perm_addr);
921*4882a593Smuzhiyun 	}
922*4882a593Smuzhiyun 
923*4882a593Smuzhiyun 	priv->cur_rssi = &p54_rssi_default;
924*4882a593Smuzhiyun 
925*4882a593Smuzhiyun 	wiphy_info(dev->wiphy, "hwaddr %pM, MAC:isl38%02x RF:%s\n",
926*4882a593Smuzhiyun 		   dev->wiphy->perm_addr, priv->version,
927*4882a593Smuzhiyun 		   p54_rf_chips[priv->rxhw]);
928*4882a593Smuzhiyun 
929*4882a593Smuzhiyun 	return 0;
930*4882a593Smuzhiyun 
931*4882a593Smuzhiyun err:
932*4882a593Smuzhiyun 	kfree(priv->iq_autocal);
933*4882a593Smuzhiyun 	kfree(priv->output_limit);
934*4882a593Smuzhiyun 	kfree(priv->curve_data);
935*4882a593Smuzhiyun 	kfree(priv->rssi_db);
936*4882a593Smuzhiyun 	kfree(priv->survey);
937*4882a593Smuzhiyun 	priv->iq_autocal = NULL;
938*4882a593Smuzhiyun 	priv->output_limit = NULL;
939*4882a593Smuzhiyun 	priv->curve_data = NULL;
940*4882a593Smuzhiyun 	priv->rssi_db = NULL;
941*4882a593Smuzhiyun 	priv->survey = NULL;
942*4882a593Smuzhiyun 
943*4882a593Smuzhiyun 	wiphy_err(dev->wiphy, "eeprom parse failed!\n");
944*4882a593Smuzhiyun 	return err;
945*4882a593Smuzhiyun }
946*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(p54_parse_eeprom);
947*4882a593Smuzhiyun 
p54_read_eeprom(struct ieee80211_hw * dev)948*4882a593Smuzhiyun int p54_read_eeprom(struct ieee80211_hw *dev)
949*4882a593Smuzhiyun {
950*4882a593Smuzhiyun 	struct p54_common *priv = dev->priv;
951*4882a593Smuzhiyun 	size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize;
952*4882a593Smuzhiyun 	int ret = -ENOMEM;
953*4882a593Smuzhiyun 	void *eeprom;
954*4882a593Smuzhiyun 
955*4882a593Smuzhiyun 	maxblocksize = EEPROM_READBACK_LEN;
956*4882a593Smuzhiyun 	if (priv->fw_var >= 0x509)
957*4882a593Smuzhiyun 		maxblocksize -= 0xc;
958*4882a593Smuzhiyun 	else
959*4882a593Smuzhiyun 		maxblocksize -= 0x4;
960*4882a593Smuzhiyun 
961*4882a593Smuzhiyun 	eeprom = kzalloc(eeprom_size, GFP_KERNEL);
962*4882a593Smuzhiyun 	if (unlikely(!eeprom))
963*4882a593Smuzhiyun 		goto free;
964*4882a593Smuzhiyun 
965*4882a593Smuzhiyun 	while (eeprom_size) {
966*4882a593Smuzhiyun 		blocksize = min(eeprom_size, maxblocksize);
967*4882a593Smuzhiyun 		ret = p54_download_eeprom(priv, eeprom + offset,
968*4882a593Smuzhiyun 					  offset, blocksize);
969*4882a593Smuzhiyun 		if (unlikely(ret))
970*4882a593Smuzhiyun 			goto free;
971*4882a593Smuzhiyun 
972*4882a593Smuzhiyun 		offset += blocksize;
973*4882a593Smuzhiyun 		eeprom_size -= blocksize;
974*4882a593Smuzhiyun 	}
975*4882a593Smuzhiyun 
976*4882a593Smuzhiyun 	ret = p54_parse_eeprom(dev, eeprom, offset);
977*4882a593Smuzhiyun free:
978*4882a593Smuzhiyun 	kfree(eeprom);
979*4882a593Smuzhiyun 	return ret;
980*4882a593Smuzhiyun }
981*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(p54_read_eeprom);
982