Commit 19c19d54 authored by Christian Lamparter's avatar Christian Lamparter Committed by John W. Linville

p54: better firmware support

This patch hopefully contains all necessary changes to support
firmwares for all devices up to atleast 2.13.3.0.
(or: LowerMAC Protocol Rev: 5.5 )

And this is a big win, since:
 * newer firmwares are more stable and reliable than the old ones.
 * no problems anymore with packages > 1399 octets (without lowering the MTU).
 * monitor mode finally works on USB for more than just a few seconds.
Signed-off-by: default avatarChristian Lamparter <chunkeey@web.de>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent e0a58eac
...@@ -19,13 +19,24 @@ enum control_frame_types { ...@@ -19,13 +19,24 @@ enum control_frame_types {
P54_CONTROL_TYPE_CHANNEL_CHANGE, P54_CONTROL_TYPE_CHANNEL_CHANGE,
P54_CONTROL_TYPE_FREQDONE, P54_CONTROL_TYPE_FREQDONE,
P54_CONTROL_TYPE_DCFINIT, P54_CONTROL_TYPE_DCFINIT,
P54_CONTROL_TYPE_FREEQUEUE = 7, P54_CONTROL_TYPE_ENCRYPTION,
P54_CONTROL_TYPE_TIM,
P54_CONTROL_TYPE_POWERMGT,
P54_CONTROL_TYPE_FREEQUEUE,
P54_CONTROL_TYPE_TXDONE, P54_CONTROL_TYPE_TXDONE,
P54_CONTROL_TYPE_PING, P54_CONTROL_TYPE_PING,
P54_CONTROL_TYPE_STAT_READBACK, P54_CONTROL_TYPE_STAT_READBACK,
P54_CONTROL_TYPE_BBP, P54_CONTROL_TYPE_BBP,
P54_CONTROL_TYPE_EEPROM_READBACK, P54_CONTROL_TYPE_EEPROM_READBACK,
P54_CONTROL_TYPE_LED P54_CONTROL_TYPE_LED,
P54_CONTROL_TYPE_GPIO,
P54_CONTROL_TYPE_TIMER,
P54_CONTROL_TYPE_MODULATION,
P54_CONTROL_TYPE_SYNTH_CONFIG,
P54_CONTROL_TYPE_DETECTOR_VALUE,
P54_CONTROL_TYPE_XBOW_SYNTH_CFG,
P54_CONTROL_TYPE_CCE_QUIET,
P54_CONTROL_TYPE_PSM_STA_UNLOCK,
}; };
struct p54_control_hdr { struct p54_control_hdr {
......
...@@ -424,11 +424,12 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) ...@@ -424,11 +424,12 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
} }
EXPORT_SYMBOL_GPL(p54_parse_eeprom); EXPORT_SYMBOL_GPL(p54_parse_eeprom);
static void p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
{ {
struct p54_rx_hdr *hdr = (struct p54_rx_hdr *) skb->data; struct p54_rx_hdr *hdr = (struct p54_rx_hdr *) skb->data;
struct ieee80211_rx_status rx_status = {0}; struct ieee80211_rx_status rx_status = {0};
u16 freq = le16_to_cpu(hdr->freq); u16 freq = le16_to_cpu(hdr->freq);
size_t header_len = sizeof(*hdr);
rx_status.signal = hdr->rssi; rx_status.signal = hdr->rssi;
/* XX correct? */ /* XX correct? */
...@@ -440,10 +441,15 @@ static void p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) ...@@ -440,10 +441,15 @@ static void p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
rx_status.mactime = le64_to_cpu(hdr->timestamp); rx_status.mactime = le64_to_cpu(hdr->timestamp);
rx_status.flag |= RX_FLAG_TSFT; rx_status.flag |= RX_FLAG_TSFT;
skb_pull(skb, sizeof(*hdr)); if (hdr->magic & cpu_to_le16(0x4000))
header_len += hdr->align[0];
skb_pull(skb, header_len);
skb_trim(skb, le16_to_cpu(hdr->len)); skb_trim(skb, le16_to_cpu(hdr->len));
ieee80211_rx_irqsafe(dev, skb, &rx_status); ieee80211_rx_irqsafe(dev, skb, &rx_status);
return -1;
} }
static void inline p54_wake_free_queues(struct ieee80211_hw *dev) static void inline p54_wake_free_queues(struct ieee80211_hw *dev)
...@@ -536,7 +542,7 @@ static void p54_rx_eeprom_readback(struct ieee80211_hw *dev, ...@@ -536,7 +542,7 @@ static void p54_rx_eeprom_readback(struct ieee80211_hw *dev,
complete(&priv->eeprom_comp); complete(&priv->eeprom_comp);
} }
static void p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb)
{ {
struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data;
...@@ -554,31 +560,19 @@ static void p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) ...@@ -554,31 +560,19 @@ static void p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb)
wiphy_name(dev->wiphy), le16_to_cpu(hdr->type)); wiphy_name(dev->wiphy), le16_to_cpu(hdr->type));
break; break;
} }
return 0;
} }
/* returns zero if skb can be reused */ /* returns zero if skb can be reused */
int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb) int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb)
{ {
u8 type = le16_to_cpu(*((__le16 *)skb->data)) >> 8; u8 type = le16_to_cpu(*((__le16 *)skb->data)) >> 8;
switch (type) {
case 0x00: if (type == 0x80)
case 0x01: return p54_rx_control(dev, skb);
p54_rx_data(dev, skb); else
return -1; return p54_rx_data(dev, skb);
case 0x4d:
/* TODO: do something better... but then again, I've never seen this happen */
printk(KERN_ERR "%s: Received fault. Probably need to restart hardware now..\n",
wiphy_name(dev->wiphy));
break;
case 0x80:
p54_rx_control(dev, skb);
break;
default:
printk(KERN_ERR "%s: unknown frame RXed (0x%02x)\n",
wiphy_name(dev->wiphy), type);
break;
}
return 0;
} }
EXPORT_SYMBOL_GPL(p54_rx); EXPORT_SYMBOL_GPL(p54_rx);
...@@ -791,6 +785,7 @@ static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type, ...@@ -791,6 +785,7 @@ static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type,
struct p54_common *priv = dev->priv; struct p54_common *priv = dev->priv;
struct p54_control_hdr *hdr; struct p54_control_hdr *hdr;
struct p54_tx_control_filter *filter; struct p54_tx_control_filter *filter;
size_t data_len;
hdr = kzalloc(sizeof(*hdr) + sizeof(*filter) + hdr = kzalloc(sizeof(*hdr) + sizeof(*filter) +
priv->tx_hdr_len, GFP_ATOMIC); priv->tx_hdr_len, GFP_ATOMIC);
...@@ -801,8 +796,6 @@ static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type, ...@@ -801,8 +796,6 @@ static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type,
filter = (struct p54_tx_control_filter *) hdr->data; filter = (struct p54_tx_control_filter *) hdr->data;
hdr->magic1 = cpu_to_le16(0x8001); hdr->magic1 = cpu_to_le16(0x8001);
hdr->len = cpu_to_le16(sizeof(*filter));
p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*filter));
hdr->type = cpu_to_le16(P54_CONTROL_TYPE_FILTER_SET); hdr->type = cpu_to_le16(P54_CONTROL_TYPE_FILTER_SET);
priv->filter_type = filter->filter_type = cpu_to_le16(filter_type); priv->filter_type = filter->filter_type = cpu_to_le16(filter_type);
...@@ -813,13 +806,25 @@ static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type, ...@@ -813,13 +806,25 @@ static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type,
memcpy(filter->bssid, bssid, ETH_ALEN); memcpy(filter->bssid, bssid, ETH_ALEN);
filter->rx_antenna = priv->rx_antenna; filter->rx_antenna = priv->rx_antenna;
filter->basic_rate_mask = cpu_to_le32(0x15F);
filter->rx_addr = cpu_to_le32(priv->rx_end);
filter->max_rx = cpu_to_le16(priv->rx_mtu);
filter->rxhw = cpu_to_le16(priv->rxhw);
filter->wakeup_timer = cpu_to_le16(500);
priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*filter), 1); if (priv->fw_var < 0x500) {
data_len = P54_TX_CONTROL_FILTER_V1_LEN;
filter->v1.basic_rate_mask = cpu_to_le32(0x15F);
filter->v1.rx_addr = cpu_to_le32(priv->rx_end);
filter->v1.max_rx = cpu_to_le16(priv->rx_mtu);
filter->v1.rxhw = cpu_to_le16(priv->rxhw);
filter->v1.wakeup_timer = cpu_to_le16(500);
} else {
data_len = P54_TX_CONTROL_FILTER_V2_LEN;
filter->v2.rx_addr = cpu_to_le32(priv->rx_end);
filter->v2.max_rx = cpu_to_le16(priv->rx_mtu);
filter->v2.rxhw = cpu_to_le16(priv->rxhw);
filter->v2.timer = cpu_to_le16(1000);
}
hdr->len = cpu_to_le16(data_len);
p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + data_len);
priv->tx(dev, hdr, sizeof(*hdr) + data_len, 1);
return 0; return 0;
} }
...@@ -829,6 +834,7 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) ...@@ -829,6 +834,7 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq)
struct p54_control_hdr *hdr; struct p54_control_hdr *hdr;
struct p54_tx_control_channel *chan; struct p54_tx_control_channel *chan;
unsigned int i; unsigned int i;
size_t data_len;
void *entry; void *entry;
hdr = kzalloc(sizeof(*hdr) + sizeof(*chan) + hdr = kzalloc(sizeof(*hdr) + sizeof(*chan) +
...@@ -841,9 +847,8 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) ...@@ -841,9 +847,8 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq)
chan = (struct p54_tx_control_channel *) hdr->data; chan = (struct p54_tx_control_channel *) hdr->data;
hdr->magic1 = cpu_to_le16(0x8001); hdr->magic1 = cpu_to_le16(0x8001);
hdr->len = cpu_to_le16(sizeof(*chan));
hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE); hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE);
p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*chan));
chan->flags = cpu_to_le16(0x1); chan->flags = cpu_to_le16(0x1);
chan->dwell = cpu_to_le16(0x0); chan->dwell = cpu_to_le16(0x0);
...@@ -895,10 +900,20 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) ...@@ -895,10 +900,20 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq)
break; break;
} }
chan->rssical_mul = cpu_to_le16(130); if (priv->fw_var < 0x500) {
chan->rssical_add = cpu_to_le16(0xfe70); /* -400 */ data_len = P54_TX_CONTROL_CHANNEL_V1_LEN;
chan->v1.rssical_mul = cpu_to_le16(130);
chan->v1.rssical_add = cpu_to_le16(0xfe70);
} else {
data_len = P54_TX_CONTROL_CHANNEL_V2_LEN;
chan->v2.rssical_mul = cpu_to_le16(130);
chan->v2.rssical_add = cpu_to_le16(0xfe70);
chan->v2.basic_rate_mask = cpu_to_le32(0x15f);
}
priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*chan), 1); hdr->len = cpu_to_le16(data_len);
p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + data_len);
priv->tx(dev, hdr, sizeof(*hdr) + data_len, 1);
return 0; return 0;
err: err:
......
...@@ -186,7 +186,7 @@ struct p54_rx_hdr { ...@@ -186,7 +186,7 @@ struct p54_rx_hdr {
u8 quality; u8 quality;
u16 unknown2; u16 unknown2;
__le64 timestamp; __le64 timestamp;
u8 data[0]; u8 align[0];
} __attribute__ ((packed)); } __attribute__ ((packed));
struct p54_frame_sent_hdr { struct p54_frame_sent_hdr {
...@@ -218,15 +218,30 @@ struct p54_tx_control_filter { ...@@ -218,15 +218,30 @@ struct p54_tx_control_filter {
u8 bssid[ETH_ALEN]; u8 bssid[ETH_ALEN];
u8 rx_antenna; u8 rx_antenna;
u8 rx_align; u8 rx_align;
union {
struct {
__le32 basic_rate_mask; __le32 basic_rate_mask;
u8 rts_rates[8]; u8 rts_rates[8];
__le32 rx_addr; __le32 rx_addr;
__le16 max_rx; __le16 max_rx;
__le16 rxhw; __le16 rxhw;
__le16 wakeup_timer; __le16 wakeup_timer;
__le16 unalloc; __le16 unalloc0;
} v1 __attribute__ ((packed));
struct {
__le32 rx_addr;
__le16 max_rx;
__le16 rxhw;
__le16 timer;
__le16 unalloc0;
__le32 unalloc1;
} v2 __attribute__ ((packed));
} __attribute__ ((packed));
} __attribute__ ((packed)); } __attribute__ ((packed));
#define P54_TX_CONTROL_FILTER_V1_LEN (sizeof(struct p54_tx_control_filter))
#define P54_TX_CONTROL_FILTER_V2_LEN (sizeof(struct p54_tx_control_filter)-8)
struct p54_tx_control_channel { struct p54_tx_control_channel {
__le16 flags; __le16 flags;
__le16 dwell; __le16 dwell;
...@@ -238,15 +253,29 @@ struct p54_tx_control_channel { ...@@ -238,15 +253,29 @@ struct p54_tx_control_channel {
u8 val_qpsk; u8 val_qpsk;
u8 val_16qam; u8 val_16qam;
u8 val_64qam; u8 val_64qam;
struct pda_pa_curve_data_sample_rev1 curve_data[8]; struct p54_pa_curve_data_sample curve_data[8];
u8 dup_bpsk; u8 dup_bpsk;
u8 dup_qpsk; u8 dup_qpsk;
u8 dup_16qam; u8 dup_16qam;
u8 dup_64qam; u8 dup_64qam;
union {
struct {
__le16 rssical_mul; __le16 rssical_mul;
__le16 rssical_add; __le16 rssical_add;
} v1 __attribute__ ((packed));
struct {
__le32 basic_rate_mask;
u8 rts_rates[8];
__le16 rssical_mul;
__le16 rssical_add;
} v2 __attribute__ ((packed));
} __attribute__ ((packed));
} __attribute__ ((packed)); } __attribute__ ((packed));
#define P54_TX_CONTROL_CHANNEL_V1_LEN (sizeof(struct p54_tx_control_channel)-12)
#define P54_TX_CONTROL_CHANNEL_V2_LEN (sizeof(struct p54_tx_control_channel))
struct p54_tx_control_led { struct p54_tx_control_led {
__le16 mode; __le16 mode;
__le16 led_temporary; __le16 led_temporary;
......
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