p54: longbow frontend support
RFC PATCH 1/3 p54: longbow frontend support
This patch adds support for stlc45xx's longbow RF-chip.
---
drivers/net/wireless/p54/p54common.c +190 -65
@@ -261,13 +261,19 @@ static int p54_convert_rev0(struct ieee8unsigned int i, j;void *source, *target; - priv->curve_data =kmalloc (cd_len,GFP_KERNEL ); + priv->curve_data =kmalloc (sizeof (*priv->curve_data) + cd_len, +GFP_KERNEL );if (!priv->curve_data)return -ENOMEM ; -memcpy (priv->curve_data, curve_data,sizeof (*curve_data)); + priv->curve_data->entries = curve_data->channels; + priv->curve_data->entry_size =sizeof (__le16) + +sizeof (*dst) * curve_data->points_per_channel; + priv->curve_data->offset = offsetof(struct pda_pa_curve_data , data); + priv->curve_data->len = cd_len; +memcpy (priv->curve_data->data, curve_data,sizeof (*curve_data)); source = curve_data->data; - target = priv->curve_data->data; + target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;for (i =0 ; i < curve_data->channels; i++) {__le16 *freq = source; source +=sizeof (__le16);
@@ -307,13 +313,19 @@ static int p54_convert_rev1(struct ieee8unsigned int i, j;void *source, *target; - priv->curve_data =kmalloc (cd_len,GFP_KERNEL ); + priv->curve_data =kmalloc (cd_len +sizeof (*priv->curve_data), +GFP_KERNEL );if (!priv->curve_data)return -ENOMEM ; -memcpy (priv->curve_data, curve_data,sizeof (*curve_data)); + priv->curve_data->entries = curve_data->channels; + priv->curve_data->entry_size =sizeof (__le16) + +sizeof (*dst) * curve_data->points_per_channel; + priv->curve_data->offset = offsetof(struct pda_pa_curve_data , data); + priv->curve_data->len = cd_len; +memcpy (priv->curve_data->data, curve_data,sizeof (*curve_data)); source = curve_data->data; - target = priv->curve_data->data; + target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;for (i =0 ; i < curve_data->channels; i++) {__le16 *freq = source; source +=sizeof (__le16);
@@ -365,6 +377,27 @@ static void p54_parse_rssical(struct iee } } +static int p54_parse_output_power_limits (struct ieee80211_hw *dev, +struct pda_entry *entry) +{ +struct p54_common *priv = dev->priv; + priv->output_limit =kmalloc (entry->data[1 ] * +sizeof (struct pda_channel_output_limit ) + +sizeof (*priv->output_limit),GFP_KERNEL ); + +if (!priv->output_limit) +return -ENOMEM ; + + priv->output_limit->entries = entry->data[1 ]; + priv->output_limit->entry_size = +sizeof (struct pda_channel_output_limit ); + +memcpy (priv->output_limit->data, &entry->data[2 ], + entry->data[1 ] *sizeof (*priv->output_limit)); + +return 0 ; +} +static int p54_parse_eeprom (struct ieee80211_hw *dev,void *eeprom,int len) {struct p54_common *priv = dev->priv;
@@ -391,9 +424,14 @@ static int p54_parse_eeprom(struct ieee8switch (le16_to_cpu (entry->code)) {case PDR_MAC_ADDRESS : +if (data_len !=ETH_ALEN ) +break ;SET_IEEE80211_PERM_ADDR (dev, entry->data);break ;case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS : +if (priv->output_limit) +break ; +if (data_len <2 ) { err = -EINVAL ; goto err;
@@ -404,17 +442,10 @@ static int p54_parse_eeprom(struct ieee8 goto err; } - priv->output_limit =kmalloc (entry->data[1 ] * -sizeof (*priv->output_limit),GFP_KERNEL ); - -if (!priv->output_limit) { - err = -ENOMEM ; + err =p54_parse_output_power_limits (dev, entry); +if (err) goto err; - } -memcpy (priv->output_limit, &entry->data[2 ], - entry->data[1 ]*sizeof (*priv->output_limit)); - priv->output_limit_len = entry->data[1 ];break ;case PDR_PRISM_PA_CAL_CURVE_DATA : { struct pda_pa_curve_data *curve_data =
@@ -463,6 +494,8 @@ static int p54_parse_eeprom(struct ieee8 }break ;case PDR_HARDWARE_PLATFORM_COMPONENT_ID : +if (data_len <2 ) +break ; priv->version = *(u8 *)(entry->data +1 );break ;case PDR_RSSI_LINEAR_APPROXIMATION :
@@ -471,6 +504,37 @@ static int p54_parse_eeprom(struct ieee8p54_parse_rssical (dev, entry->data, data_len,le16_to_cpu (entry->code));break ; +case PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM : +if (data_len !=sizeof (priv->rssical_db)) { + err = -EINVAL ; + goto err; + } +memcpy (&priv->rssical_db, entry->data, data_len); +break ; +case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM : { +struct pda_custom_wrapper *tm = (void *) entry->data; +if (priv->output_limit !=NULL ) +break ; +if (data_len <sizeof (*tm)) +break ; +if ((tm->entries * tm->entry_size != tm->len) || + (tm->len +sizeof (*tm) != data_len)) +break ; + priv->output_limit =kmemdup (tm, data_len,GFP_KERNEL ); + } +break ; +case PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM : { +struct pda_custom_wrapper *pda = (void *) entry->data; +if (priv->curve_data !=NULL ) +break ; +if (data_len <sizeof (*pda)) +break ; +if ((pda->entries * pda->entry_size != pda->len) || + (pda->len +sizeof (*pda) != data_len)) +break ; + priv->curve_data =kmemdup (pda, data_len,GFP_KERNEL ); + } +break ;case PDR_END :/* make it overrun */ entry_len = len;
@@ -515,7 +579,7 @@ static int p54_parse_eeprom(struct ieee8 } 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;
@@ -564,7 +628,14 @@ static int p54_rssi_to_dbm(struct ieee80struct p54_common *priv = dev->priv;int band = dev->conf.channel->band; -return ((rssi * priv->rssical_db[band].mul) /64 + +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 ; }
@@ -1411,8 +1482,14 @@ static int p54_tx(struct ieee80211_hw *dmemset (txhdr->durations,0 ,sizeof (txhdr->durations)); txhdr->tx_antenna = (info->antenna_sel_tx ==0 ) ?2 : info->antenna_sel_tx -1 ; - 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;
@@ -1429,10 +1506,8 @@ static int p54_tx(struct ieee80211_hw *d err:skb_pull (skb,sizeof (*hdr) +sizeof (*txhdr) + padding); -if (current_queue) { - current_queue->len--; - current_queue->count--; - } + current_queue->len--; + current_queue->count--;return NETDEV_TX_BUSY ; }
@@ -1507,85 +1582,135 @@ static int p54_scan(struct ieee80211_hw {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;__le16 freq =cpu_to_le16 (dev->conf.channel->center_freq);int band = dev->conf.channel->band; - skb =p54_alloc_skb (dev,P54_HDR_FLAG_CONTROL_OPSET ,sizeof (*chan) + -sizeof (struct p54_hdr ),P54_CONTROL_TYPE_SCAN , -GFP_ATOMIC ); + skb =p54_alloc_skb (dev,P54_HDR_FLAG_CONTROL_OPSET ,sizeof (*hdr) + +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->padding1,0 ,sizeof (chan->padding1)); - chan->mode =cpu_to_le16 (mode); - chan->dwell =cpu_to_le16 (dwell); + head = (struct p54_scan_head *)skb_put (skb,sizeof (*head)); +memset (head->scanning,0 ,sizeof (head->scanning)); + 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; -for (i =0 ; i < priv->output_limit_len; i++) { -if (priv->output_limit[i].freq != freq) +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++) { +__le16 *entry_freq = (void *) (priv->output_limit->data + + priv->output_limit->entry_size * i); + +if (*entry_freq != freq)continue ; - chan->val_barker =0x38 ; - chan->val_bpsk = chan->dup_bpsk = - priv->output_limit[i].val_bpsk; - chan->val_qpsk = chan->dup_qpsk = - priv->output_limit[i].val_qpsk; - chan->val_16qam = chan->dup_16qam = - priv->output_limit[i].val_16qam; - chan->val_64qam = chan->dup_64qam = - priv->output_limit[i].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_len) +if (i == priv->output_limit->entries) goto err; - entry = priv->curve_data->data; -for (i =0 ; i < priv->curve_data->channels; i++) { + entry = (void *)(priv->curve_data->data + priv->curve_data->offset); +for (i =0 ; i < priv->curve_data->entries; i++) {if (*((__le16 *)entry) != freq) { - entry +=sizeof (__le16); - entry +=sizeof (struct p54_pa_curve_data_sample ) * - priv->curve_data->points_per_channel; + entry += priv->curve_data->entry_size;continue ; } - entry +=sizeof (__le16); - chan->pa_points_per_curve =8 ; -memset (chan->curve_data,0 ,sizeof (*chan->curve_data)); -memcpy (chan->curve_data, entry, -sizeof (struct p54_pa_curve_data_sample ) * -min ((u8 )8 , priv->curve_data->points_per_channel)); +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)); +memcpy (chan->curve_data, entry, +sizeof (struct p54_pa_curve_data_sample ) * +min ((u8 )8 , curve_data->points_per_channel)); + }break ; } -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 ) { + rate = (void *)skb_put (skb,sizeof (*rate)); + rate->basic_rate_mask =cpu_to_le32 (priv->basic_rate_mask); +/* TODO: initialize a RTS rate array */ +memset (rate->rts_rates,0 ,8 ); + } + + 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); } + + hdr = (struct p54_hdr *) skb->data; + hdr->len = skb->len -sizeof (*hdr); + priv->tx (dev, skb);return 0 ; err:printk (KERN_ERR "%s: frequency change failed\n" ,wiphy_name (dev->wiphy)); -kfree_skb (skb); +p54_free_skb (dev, skb);return -EINVAL ; }
drivers/net/wireless/p54/p54common.h +72 -19
140 lines not on this page · raw message
drivers/net/wireless/p54/p54.h +2 -3
@@ -101,9 +101,8 @@ struct p54_common {u8 bssid[ETH_ALEN ];struct pda_iq_autocal_entry *iq_autocal;unsigned int iq_autocal_len; -struct pda_channel_output_limit *output_limit; -unsigned int output_limit_len; -struct pda_pa_curve_data *curve_data; +struct pda_custom_wrapper *output_limit; +struct pda_custom_wrapper *curve_data;struct p54_rssi_linear_approximation rssical_db[IEEE80211_NUM_BANDS ];unsigned int filter_flags;bool use_short_slot;