Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6917f506 authored by Christian Lamparter's avatar Christian Lamparter Committed by John W. Linville
Browse files

p54: longbow frontend support



This patch adds support for longbow RF chip.

Signed-off-by: default avatarChristian Lamparter <chunkeey@web.de>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 83cf1b6e
Loading
Loading
Loading
Loading
+104 −37
Original line number Diff line number Diff line
@@ -651,7 +651,7 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
	}

	priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
	if (priv->rxhw == 4)
	if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW)
		p54_init_xbow_synth(dev);
	if (!(synth & PDR_SYNTH_24_GHZ_DISABLED))
		dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz;
@@ -704,6 +704,13 @@ static int p54_rssi_to_dbm(struct ieee80211_hw *dev, int rssi)
	struct p54_common *priv = dev->priv;
	int band = dev->conf.channel->band;

	if (priv->rxhw != PDR_SYNTH_FRONTEND_LONGBOW)
		return ((rssi * priv->rssical_db[band].mul) / 64 +
			 priv->rssical_db[band].add) / 4;
	else
		/*
		 * TODO: find the correct formula
		 */
		return ((rssi * priv->rssical_db[band].mul) / 64 +
			 priv->rssical_db[band].add) / 4;
}
@@ -1612,8 +1619,13 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
	memset(txhdr->durations, 0, sizeof(txhdr->durations));
	txhdr->tx_antenna = ((info->antenna_sel_tx == 0) ?
		2 : info->antenna_sel_tx - 1) & priv->tx_diversity_mask;
	txhdr->output_power = priv->output_power;
	txhdr->cts_rate = cts_rate;
	if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
		txhdr->longbow.cts_rate = cts_rate;
		txhdr->longbow.output_power = cpu_to_le16(priv->output_power);
	} else {
		txhdr->normal.output_power = priv->output_power;
		txhdr->normal.cts_rate = cts_rate;
	}
	if (padding)
		txhdr->align[0] = padding;

@@ -1715,47 +1727,77 @@ static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell)
{
	struct p54_common *priv = dev->priv;
	struct sk_buff *skb;
	struct p54_scan *chan;
	struct p54_hdr *hdr;
	struct p54_scan_head *head;
	struct p54_iq_autocal_entry *iq_autocal;
	union p54_scan_body_union *body;
	struct p54_scan_tail_rate *rate;
	struct pda_rssi_cal_entry *rssi;
	unsigned int i;
	void *entry;
	int band = dev->conf.channel->band;
	__le16 freq = cpu_to_le16(dev->conf.channel->center_freq);

	skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*chan),
	skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*head) +
			    2 + sizeof(*iq_autocal) + sizeof(*body) +
			    sizeof(*rate) + 2 * sizeof(*rssi),
			    P54_CONTROL_TYPE_SCAN, GFP_ATOMIC);
	if (!skb)
		return -ENOMEM;

	chan = (struct p54_scan *) skb_put(skb, sizeof(*chan));
	memset(chan->scan_params, 0, sizeof(chan->scan_params));
	chan->mode = cpu_to_le16(mode);
	chan->dwell = cpu_to_le16(dwell);
	head = (struct p54_scan_head *) skb_put(skb, sizeof(*head));
	memset(head->scan_params, 0, sizeof(head->scan_params));
	head->mode = cpu_to_le16(mode);
	head->dwell = cpu_to_le16(dwell);
	head->freq = freq;

	if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
		__le16 *pa_power_points = (__le16 *) skb_put(skb, 2);
		*pa_power_points = cpu_to_le16(0x0c);
	}

	iq_autocal = (void *) skb_put(skb, sizeof(*iq_autocal));
	for (i = 0; i < priv->iq_autocal_len; i++) {
		if (priv->iq_autocal[i].freq != freq)
			continue;

		memcpy(&chan->iq_autocal, &priv->iq_autocal[i],
		       sizeof(*priv->iq_autocal));
		memcpy(iq_autocal, &priv->iq_autocal[i].params,
		       sizeof(struct p54_iq_autocal_entry));
		break;
	}
	if (i == priv->iq_autocal_len)
		goto err;

	if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW)
		body = (void *) skb_put(skb, sizeof(body->longbow));
	else
		body = (void *) skb_put(skb, sizeof(body->normal));

	for (i = 0; i < priv->output_limit->entries; i++) {
		struct pda_channel_output_limit *limits;
		__le16 *entry_freq = (void *) (priv->output_limit->data +
				     priv->output_limit->entry_size * i);

		if (*entry_freq != freq)
			continue;

		limits = (void *) entry_freq;
		chan->val_barker = 0x38;
		chan->val_bpsk = chan->dup_bpsk = limits->val_bpsk;
		chan->val_qpsk = chan->dup_qpsk = limits->val_qpsk;
		chan->val_16qam = chan->dup_16qam = limits->val_16qam;
		chan->val_64qam = chan->dup_64qam = limits->val_64qam;
		if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
			memcpy(&body->longbow.power_limits,
			       (void *) entry_freq + sizeof(__le16),
			       priv->output_limit->entry_size);
		} else {
			struct pda_channel_output_limit *limits =
			       (void *) entry_freq;

			body->normal.val_barker = 0x38;
			body->normal.val_bpsk = body->normal.dup_bpsk =
				limits->val_bpsk;
			body->normal.val_qpsk = body->normal.dup_qpsk =
				limits->val_qpsk;
			body->normal.val_16qam = body->normal.dup_16qam =
				limits->val_16qam;
			body->normal.val_64qam = body->normal.dup_64qam =
				limits->val_64qam;
		}
		break;
	}
	if (i == priv->output_limit->entries)
@@ -1763,34 +1805,59 @@ static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell)

	entry = (void *)(priv->curve_data->data + priv->curve_data->offset);
	for (i = 0; i < priv->curve_data->entries; i++) {
		struct pda_pa_curve_data *curve_data;
		if (*((__le16 *)entry) != freq) {
			entry += priv->curve_data->entry_size;
			continue;
		}

		if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
			memcpy(&body->longbow.curve_data,
				(void *) entry + sizeof(__le16),
				priv->curve_data->entry_size);
		} else {
			struct p54_scan_body *chan = &body->normal;
			struct pda_pa_curve_data *curve_data =
				(void *) priv->curve_data->data;

			entry += sizeof(__le16);
			chan->pa_points_per_curve = 8;
			memset(chan->curve_data, 0, sizeof(*chan->curve_data));
		curve_data = (void *) priv->curve_data->data;

			memcpy(chan->curve_data, entry,
			       sizeof(struct p54_pa_curve_data_sample) *
		       min_t(u8, 8, curve_data->points_per_channel));
			       min((u8)8, curve_data->points_per_channel));
		}
		break;
	}
	if (i == priv->curve_data->entries)
		goto err;

	if (priv->fw_var < 0x500) {
		chan->v1_rssi.mul = cpu_to_le16(priv->rssical_db[band].mul);
		chan->v1_rssi.add = cpu_to_le16(priv->rssical_db[band].add);
	} else {
		chan->v2.rssi.mul = cpu_to_le16(priv->rssical_db[band].mul);
		chan->v2.rssi.add = cpu_to_le16(priv->rssical_db[band].add);
		chan->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
		memset(chan->v2.rts_rates, 0, 8);
	if ((priv->fw_var >= 0x500) && (priv->fw_var < 0x509)) {
		rate = (void *) skb_put(skb, sizeof(*rate));
		rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
		for (i = 0; i < sizeof(rate->rts_rates); i++)
			rate->rts_rates[i] = i;
	}

	rssi = (struct pda_rssi_cal_entry *) skb_put(skb, sizeof(*rssi));
	rssi->mul = cpu_to_le16(priv->rssical_db[band].mul);
	rssi->add = cpu_to_le16(priv->rssical_db[band].add);
	if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
		/* Longbow frontend needs ever more */
		rssi = (void *) skb_put(skb, sizeof(*rssi));
		rssi->mul = cpu_to_le16(priv->rssical_db[band].longbow_unkn);
		rssi->add = cpu_to_le16(priv->rssical_db[band].longbow_unk2);
	}

	if (priv->fw_var >= 0x509) {
		rate = (void *) skb_put(skb, sizeof(*rate));
		rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
		for (i = 0; i < sizeof(rate->rts_rates); i++)
			rate->rts_rates[i] = i;
	}

	hdr = (struct p54_hdr *) skb->data;
	hdr->len = cpu_to_le16(skb->len - sizeof(*hdr));

	priv->tx(dev, skb);
	return 0;

+56 −16
Original line number Diff line number Diff line
@@ -26,6 +26,11 @@ struct bootrec {
} __attribute__((packed));

#define PDR_SYNTH_FRONTEND_MASK		0x0007
#define PDR_SYNTH_FRONTEND_DUETTE3	0x0001
#define PDR_SYNTH_FRONTEND_DUETTE2	0x0002
#define PDR_SYNTH_FRONTEND_FRISBEE	0x0003
#define PDR_SYNTH_FRONTEND_XBOW		0x0004
#define PDR_SYNTH_FRONTEND_LONGBOW	0x0005
#define PDR_SYNTH_IQ_CAL_MASK		0x0018
#define PDR_SYNTH_IQ_CAL_PA_DETECTOR	0x0000
#define PDR_SYNTH_IQ_CAL_DISABLED	0x0008
@@ -125,9 +130,13 @@ struct eeprom_pda_wrap {
	u8 data[0];
} __attribute__ ((packed));

struct p54_iq_autocal_entry {
	__le16 iq_param[4];
} __attribute__ ((packed));

struct pda_iq_autocal_entry {
        __le16 freq;
        __le16 iq_param[4];
	struct p54_iq_autocal_entry params;
} __attribute__ ((packed));

struct pda_channel_output_limit {
@@ -186,6 +195,21 @@ struct pda_country {
	u8 flags;
} __attribute__ ((packed));

/*
 * Warning: Longbow's structures are bogus.
 */
struct p54_channel_output_limit_longbow {
	__le16 rf_power_points[12];
} __attribute__ ((packed));

struct p54_pa_curve_data_sample_longbow {
	__le16 rf_power;
	__le16 pa_detector;
	struct {
		__le16 data[4];
	} points[3] __attribute__ ((packed));
} __attribute__ ((packed));

struct pda_custom_wrapper {
	__le16 entries;
	__le16 entry_size;
@@ -381,9 +405,18 @@ struct p54_tx_data {
	u8 backlog;
	__le16 durations[4];
	u8 tx_antenna;
	union {
		struct {
			u8 cts_rate;
			__le16 output_power;
		} __attribute__((packed)) longbow;
		struct {
			u8 output_power;
			u8 cts_rate;
	u8 unalloc2[3];
			u8 unalloc;
		} __attribute__ ((packed)) normal;
	} __attribute__ ((packed));
	u8 unalloc2[2];
	u8 align[0];
} __attribute__ ((packed));

@@ -444,11 +477,14 @@ struct p54_setup_mac {
#define P54_SCAN_ACTIVE BIT(2)
#define P54_SCAN_FILTER BIT(3)

struct p54_scan {
struct p54_scan_head {
	__le16 mode;
	__le16 dwell;
	u8 scan_params[20];
	struct pda_iq_autocal_entry iq_autocal;
	__le16 freq;
} __attribute__ ((packed));

struct p54_scan_body {
	u8 pa_points_per_curve;
	u8 val_barker;
	u8 val_bpsk;
@@ -460,19 +496,23 @@ struct p54_scan {
	u8 dup_qpsk;
	u8 dup_16qam;
	u8 dup_64qam;
	union {
		struct pda_rssi_cal_entry v1_rssi;
} __attribute__ ((packed));

		struct {
			__le32 basic_rate_mask;
			u8 rts_rates[8];
			struct pda_rssi_cal_entry rssi;
		} v2 __attribute__ ((packed));
struct p54_scan_body_longbow {
	struct p54_channel_output_limit_longbow power_limits;
	struct p54_pa_curve_data_sample_longbow curve_data[8];
	__le16 unkn[6];		/* maybe more power_limits or rate_mask */
} __attribute__ ((packed));

union p54_scan_body_union {
	struct p54_scan_body normal;
	struct p54_scan_body_longbow longbow;
} __attribute__ ((packed));

#define P54_SCAN_V1_LEN 0x70
#define P54_SCAN_V2_LEN 0x7c
struct p54_scan_tail_rate {
	__le32 basic_rate_mask;
	u8 rts_rates[8];
} __attribute__ ((packed));

struct p54_led {
	__le16 mode;