This patch adds the necessary changes to support LM87 firmwares.
Signed-off-by: Christian Lamparter <[email protected]>
---
John,
this one should go into wireless-next.
---
diff -Nurp a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
--- a/drivers/net/wireless/p54/p54common.c 2008-09-01 22:25:35.000000000 +0200
+++ b/drivers/net/wireless/p54/p54common.c 2008-09-02 21:29:47.000000000 +0200
@@ -93,7 +93,10 @@ int p54_parse_firmware(struct ieee80211_
u32 code = le32_to_cpu(bootrec->code);
switch (code) {
case BR_CODE_COMPONENT_ID:
- switch (be32_to_cpu(*(__be32 *)bootrec->data)) {
+ priv->fw_interface =
+ be32_to_cpu(*(__be32 *)bootrec->data);
+
+ switch (priv->fw_interface) {
case FW_FMAC:
printk(KERN_INFO "p54: FreeMAC firmware\n");
break;
@@ -104,7 +107,7 @@ int p54_parse_firmware(struct ieee80211_
printk(KERN_INFO "p54: LM86 firmware\n");
break;
case FW_LM87:
- printk(KERN_INFO "p54: LM87 firmware - not supported yet!\n");
+ printk(KERN_INFO "p54: LM87 firmware\n");
break;
default:
printk(KERN_INFO "p54: unknown firmware\n");
diff -Nurp a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h
--- a/drivers/net/wireless/p54/p54common.h 2008-09-01 01:56:53.000000000 +0200
+++ b/drivers/net/wireless/p54/p54common.h 2008-09-02 19:39:10.000000000 +0200
@@ -50,11 +50,6 @@ struct bootrec_desc {
#define BR_CODE_END_OF_BRA 0xFF0000FF
#define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF
-#define FW_FMAC 0x464d4143
-#define FW_LM86 0x4c4d3836
-#define FW_LM87 0x4c4d3837
-#define FW_LM20 0x4c4d3230
-
/* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */
struct pda_entry {
diff -Nurp a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h
--- a/drivers/net/wireless/p54/p54.h 2008-09-01 02:20:25.000000000 +0200
+++ b/drivers/net/wireless/p54/p54.h 2008-09-02 19:39:26.000000000 +0200
@@ -42,6 +42,11 @@ struct p54_control_hdr {
#define ISL38XX_DEV_FIRMWARE_ADDR 0x20000
+#define FW_FMAC 0x464d4143
+#define FW_LM86 0x4c4d3836
+#define FW_LM87 0x4c4d3837
+#define FW_LM20 0x4c4d3230
+
struct p54_common {
u32 rx_start;
u32 rx_end;
@@ -68,6 +73,7 @@ struct p54_common {
unsigned int tx_hdr_len;
void *cached_vdcf;
unsigned int fw_var;
+ unsigned int fw_interface;
struct ieee80211_tx_queue_stats tx_stats[8];
void *eeprom;
struct completion eeprom_comp;
diff -Nurp a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
--- a/drivers/net/wireless/p54/p54usb.c 2008-09-01 22:23:46.000000000 +0200
+++ b/drivers/net/wireless/p54/p54usb.c 2008-09-02 21:28:36.000000000 +0200
@@ -91,8 +91,13 @@ static void p54u_rx_cb(struct urb *urb)
skb_unlink(skb, &priv->rx_queue);
skb_put(skb, urb->actual_length);
- if (!priv->hw_type)
- skb_pull(skb, sizeof(struct net2280_tx_hdr));
+
+ if (priv->hw_type == P54U_NET2280)
+ skb_pull(skb, priv->common.tx_hdr_len);
+ if (priv->common.fw_interface == FW_LM87) {
+ skb_pull(skb, 4);
+ skb_put(skb, 4);
+ }
if (p54_rx(dev, skb)) {
skb = dev_alloc_skb(priv->common.rx_mtu + 32);
@@ -109,9 +114,12 @@ static void p54u_rx_cb(struct urb *urb)
urb->context = skb;
skb_queue_tail(&priv->rx_queue, skb);
} else {
- if (!priv->hw_type)
- skb_push(skb, sizeof(struct net2280_tx_hdr));
-
+ if (priv->hw_type == P54U_NET2280)
+ skb_push(skb, priv->common.tx_hdr_len);
+ if (priv->common.fw_interface == FW_LM87) {
+ skb_push(skb, 4);
+ skb_put(skb, 4);
+ }
skb_reset_tail_pointer(skb);
skb_trim(skb, 0);
if (urb->transfer_buffer != skb_tail_pointer(skb)) {
@@ -210,6 +218,42 @@ static void p54u_tx_3887(struct ieee8021
usb_submit_urb(data_urb, GFP_ATOMIC);
}
+__le32 p54u_lm87_chksum(const u32 *data, size_t length)
+{
+ __le32 chk = 0;
+
+ length >>= 2;
+ while (length--) {
+ chk ^= cpu_to_le32(*data++);
+ chk = (chk >> 5) ^ (chk << 3);
+ }
+
+ return chk;
+}
+
+static void p54u_tx_lm87(struct ieee80211_hw *dev,
+ struct p54_control_hdr *data,
+ size_t len, int free_on_tx)
+{
+ struct p54u_priv *priv = dev->priv;
+ struct urb *data_urb;
+ struct lm87_tx_hdr *hdr = (void *)data - sizeof(*hdr);
+
+ data_urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!data_urb)
+ return;
+
+ hdr->chksum = p54u_lm87_chksum((u32 *)data, len);
+ hdr->device_addr = data->req_id;
+
+ usb_fill_bulk_urb(data_urb, priv->udev,
+ usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), hdr,
+ len + sizeof(*hdr), free_on_tx ? p54u_tx_free_cb : p54u_tx_cb,
+ dev);
+
+ usb_submit_urb(data_urb, GFP_ATOMIC);
+}
+
static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr *data,
size_t len, int free_on_tx)
{
@@ -776,21 +820,23 @@ static int __devinit p54u_probe(struct u
}
}
priv->common.open = p54u_open;
-
+ priv->common.stop = p54u_stop;
if (recognized_pipes < P54U_PIPE_NUMBER) {
priv->hw_type = P54U_3887;
- priv->common.tx = p54u_tx_3887;
+ err = p54u_upload_firmware_3887(dev);
+ if (priv->common.fw_interface == FW_LM87) {
+ dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
+ priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
+ priv->common.tx = p54u_tx_lm87;
+ } else
+ priv->common.tx = p54u_tx_3887;
} else {
+ priv->hw_type = P54U_NET2280;
dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
priv->common.tx = p54u_tx_net2280;
- }
- priv->common.stop = p54u_stop;
-
- if (priv->hw_type)
- err = p54u_upload_firmware_3887(dev);
- else
err = p54u_upload_firmware_net2280(dev);
+ }
if (err)
goto err_free_dev;
diff -Nurp a/drivers/net/wireless/p54/p54usb.h b/drivers/net/wireless/p54/p54usb.h
--- a/drivers/net/wireless/p54/p54usb.h 2008-09-01 01:56:53.000000000 +0200
+++ b/drivers/net/wireless/p54/p54usb.h 2008-09-02 19:23:52.000000000 +0200
@@ -72,6 +72,11 @@ struct net2280_tx_hdr {
u8 padding[8];
} __attribute__((packed));
+struct lm87_tx_hdr {
+ __le32 device_addr;
+ __le32 chksum;
+} __attribute__((packed));
+
/* Some flags for the isl hardware registers controlling DMA inside the
* chip */
#define ISL38XX_DMA_STATUS_DONE 0x00000001
On Wed, 2008-09-03 at 02:00 +0200, Christian Lamparter wrote:
> whats the main difference between be32_to_cpu vs be32_to_cpus vs be32_to_cpup?
> Does the extra p just stand for something like "pointer"?
Yes. See include/linux/byteorder/generic.h
>
> hmm,
> if yes, >>*<<(__be32 *)bootrec->data.
> if no, please tell me more about it ;-).
The pointer versions take the pointer. They do the cast and the
dereference for you. The cast in your code should be unnecessary.
The in-situ version don't return anything; they put the result into the
original variable.
--
Regards,
Pavel Roskin
On Tue, Sep 2, 2008 at 10:39 PM, Christian Lamparter <[email protected]> wrote:
> This patch adds the necessary changes to support LM87 firmwares.
>
> Signed-off-by: Christian Lamparter <[email protected]>
> ---
> John,
>
> this one should go into wireless-next.
> ---
> diff -Nurp a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
> --- a/drivers/net/wireless/p54/p54common.c 2008-09-01 22:25:35.000000000 +0200
> +++ b/drivers/net/wireless/p54/p54common.c 2008-09-02 21:29:47.000000000 +0200
> @@ -93,7 +93,10 @@ int p54_parse_firmware(struct ieee80211_
> u32 code = le32_to_cpu(bootrec->code);
> switch (code) {
> case BR_CODE_COMPONENT_ID:
> - switch (be32_to_cpu(*(__be32 *)bootrec->data)) {
> + priv->fw_interface =
> + be32_to_cpu(*(__be32 *)bootrec->data);
what about be32_to_cpup?
Tomas
On Sunday 07 September 2008 01:33:29 Larry Finger wrote:
> Chr wrote:
> > But, for newer firmwares you'll need "p54: better firmware support"
> > (cc4b0cbf4ab) as well. This changes were merged about 25-26 hours ago
> > into wireless-testing, the only thing that isn't in yet is 802.11a
> > support....
> >
> > the LM87 firmware is this one:
> > http://daemonizer.de/prism54/prism54-fw/fw-usb/2.13.1.0.arm.1
> >
> > This link can be found on the driver's site too:
> > http://linuxwireless.org/en/users/Drivers/p54
>
> Thanks. That one fixed the ping problem. I had the latest
> wireless-testing, and have added the patches you posted earlier today.
>
Well, since you already do some testing here. Want more? ;-)
I will be off for about 4-5 weeks and it would be very nice if someone with lots of broadcom
hardware can test if the p54 works ADHOC & AP mode with them.
i've already (successfully) tested Intel's 2915 & 4965, several atheros chipsets and another prism54
on different operating systems.
But there could be problems with some broadcom chips.
Regards,
Chr
---
diff -Nurp a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
--- a/drivers/net/wireless/p54/p54common.c 2008-09-06 14:09:16.000000000 +0200
+++ b/drivers/net/wireless/p54/p54common.c 2008-09-07 02:04:31.000000000 +0200
@@ -589,10 +589,19 @@ static void p54_rx_frame_sent(struct iee
else
info->status.excessive_retries = 1;
}
+ if (payload->status & 0x04)
+ info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
+ info->status.retry_count = payload->retries - 1;
info->status.retry_count = payload->retries - 1;
info->status.ack_signal = p54_rssi_to_dbm(dev,
le16_to_cpu(payload->ack_rssi));
skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
+ if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
+ struct ieee80211_hdr *ieee80211hdr =
+ (struct ieee80211_hdr *)entry->data;
+ ieee80211hdr->seq_ctrl |=
+ cpu_to_le16(payload->seq);
+ }
ieee80211_tx_status_irqsafe(dev, entry);
goto out;
} else
@@ -803,25 +812,130 @@ free:
}
EXPORT_SYMBOL_GPL(p54_read_eeprom);
+static int p54_sta_unlock(struct ieee80211_hw *dev, u8 *addr)
+{
+ struct p54_common *priv = dev->priv;
+ struct p54_control_hdr *hdr;
+ struct p54_tx_control_sta_unlock *sta;
+
+ if (is_multicast_ether_addr(addr))
+ return 0;
+
+ hdr = kmalloc(sizeof(*hdr) + sizeof(*sta) +
+ priv->tx_hdr_len, GFP_ATOMIC);
+ if (!hdr)
+ return -ENOMEM;
+
+ hdr = (void *)hdr + priv->tx_hdr_len;
+ hdr->magic1 = cpu_to_le16(0x8001);
+ hdr->len = cpu_to_le16(sizeof(*sta));
+ hdr->type = cpu_to_le16(P54_CONTROL_TYPE_PSM_STA_UNLOCK);
+ p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*sta));
+
+ sta = (struct p54_tx_control_sta_unlock *) hdr->data;
+ memcpy(sta->addr, addr, ETH_ALEN);
+
+ priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*sta), 1);
+
+ return 0;
+}
+
+static int p54_set_tim(struct ieee80211_hw *dev, int aid, int set)
+{
+ struct p54_common *priv = dev->priv;
+ struct p54_control_hdr *hdr;
+ struct p54_tx_control_tim *tim;
+
+ hdr = kmalloc(sizeof(*hdr) + sizeof(*tim) +
+ priv->tx_hdr_len, GFP_KERNEL);
+ if (!hdr)
+ return -ENOMEM;
+
+ hdr = (void *)hdr + priv->tx_hdr_len;
+ hdr->magic1 = cpu_to_le16(0x8001);
+ hdr->len = cpu_to_le16(sizeof(*tim));
+ hdr->type = cpu_to_le16(P54_CONTROL_TYPE_TIM);
+ p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*tim));
+
+ tim = (struct p54_tx_control_tim *) hdr->data;
+ tim->count = 1;
+ tim->entry[0] = cpu_to_le16(set ? (aid | 0x8000) : aid);
+
+ priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*tim), 1);
+
+ return 0;
+}
+
+static int p54_tx_fill_header(struct ieee80211_hw *dev,
+ struct ieee80211_hdr *hdr, struct ieee80211_tx_info *info,
+ u8 *queue, u16 *flags, u16 *aid)
+{
+ struct p54_common *priv = dev->priv;
+ u16 fc = le16_to_cpu(hdr->frame_control);
+ int ret = 1;
+
+ if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)
+ switch (fc & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_PROBE_RESP:
+ *aid = 0;
+ *queue = 2;
+ *flags = 0x22;
+ return 0;
+ case IEEE80211_STYPE_BEACON:
+ *aid = 0;
+ *queue = 0;
+ *flags = 0x02;
+ return 0;
+ default:
+ *queue = 2;
+ ret = 0;
+ }
+ else
+ *queue += 4;
+
+ if (is_multicast_ether_addr(hdr->addr1)) {
+ *queue = 3;
+ *aid = 0;
+ return 0;
+ }
+
+ if (priv->mode != IEEE80211_IF_TYPE_STA) {
+ *aid = info->control.aid;
+ if (!info->control.aid)
+ *flags = 0x20;
+ } else
+ *aid = 1;
+
+ return ret;
+}
+
static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_tx_queue_stats *current_queue;
+ struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
struct p54_common *priv = dev->priv;
struct p54_control_hdr *hdr;
- struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
struct p54_tx_control_allocdata *txhdr;
size_t padding, len;
- u8 rate;
- u8 cts_rate = 0x20;
+ u16 aid, hdr_flags = 0x0000;
+ u8 queue, rate, cts_rate = 0x20;
+
+ queue = skb_get_queue_mapping(skb);
- current_queue = &priv->tx_stats[skb_get_queue_mapping(skb) + 4];
- if (unlikely(current_queue->len > current_queue->limit))
- return NETDEV_TX_BUSY;
- current_queue->len++;
- current_queue->count++;
- if (current_queue->len == current_queue->limit)
- ieee80211_stop_queue(dev, skb_get_queue_mapping(skb));
+ if (likely(p54_tx_fill_header(dev, ieee80211hdr, info,
+ &queue, &hdr_flags, &aid))) {
+ current_queue = &priv->tx_stats[queue];
+ if (unlikely(current_queue->len > current_queue->limit))
+ return NETDEV_TX_BUSY;
+ current_queue->len++;
+ current_queue->count++;
+ if (current_queue->len == current_queue->limit)
+ ieee80211_stop_queue(dev, skb_get_queue_mapping(skb));
+ }
+
+ if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
+ p54_sta_unlock(dev, ieee80211hdr->addr1);
padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3;
len = skb->len;
@@ -831,13 +945,12 @@ static int p54_tx(struct ieee80211_hw *d
hdr = (struct p54_control_hdr *) skb_push(skb, sizeof(*hdr));
if (padding)
- hdr->magic1 = cpu_to_le16(0x4010);
- else
- hdr->magic1 = cpu_to_le16(0x0010);
+ hdr_flags = 0x4000;
+
+ hdr->magic1 = cpu_to_le16(hdr_flags);
hdr->len = cpu_to_le16(len);
- hdr->type = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : cpu_to_le16(1);
+ hdr->type = cpu_to_le16(aid);
hdr->retry1 = hdr->retry2 = info->control.retry_limit;
-
/* TODO: add support for alternate retry TX rates */
rate = ieee80211_get_tx_rate(dev, info)->hw_value;
if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE) {
@@ -854,7 +967,7 @@ static int p54_tx(struct ieee80211_hw *d
memset(txhdr->rateset, rate, 8);
txhdr->key_type = 0;
txhdr->key_len = 0;
- txhdr->hw_queue = skb_get_queue_mapping(skb) + 4;
+ txhdr->hw_queue = queue;
txhdr->tx_antenna = (info->antenna_sel_tx == 0) ?
2 : info->antenna_sel_tx - 1;
txhdr->output_power = priv->output_power;
@@ -870,17 +983,12 @@ static int p54_tx(struct ieee80211_hw *d
* patch places the sequence number in the hardware state, which
* limits us to a single virtual state.
*/
- if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
- if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
- priv->seqno += 0x10;
- ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
- ieee80211hdr->seq_ctrl |= cpu_to_le16(priv->seqno);
- }
/* modifies skb->cb and with it info, so must be last! */
p54_assign_address(dev, skb, hdr, skb->len);
priv->tx(dev, hdr, skb->len, 0);
return 0;
+
}
static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type,
@@ -1170,6 +1278,9 @@ static int p54_add_interface(struct ieee
switch (conf->type) {
case IEEE80211_IF_TYPE_STA:
+ case IEEE80211_IF_TYPE_AP:
+ case IEEE80211_IF_TYPE_MNTR:
+ case IEEE80211_IF_TYPE_IBSS:
priv->mode = conf->type;
break;
default:
@@ -1184,6 +1295,15 @@ static int p54_add_interface(struct ieee
case IEEE80211_IF_TYPE_STA:
p54_set_filter(dev, 1, NULL);
break;
+ case IEEE80211_IF_TYPE_IBSS:
+ p54_set_filter(dev, 0x02, NULL);
+ break;
+ case IEEE80211_IF_TYPE_MNTR:
+ p54_set_filter(dev, 0x10, NULL);
+ break;
+ case IEEE80211_IF_TYPE_AP:
+ p54_set_filter(dev, 0x04, NULL);
+ break;
default:
BUG(); /* impossible */
break;
@@ -1211,25 +1331,114 @@ static int p54_config(struct ieee80211_h
mutex_lock(&priv->conf_mutex);
priv->rx_antenna = (conf->antenna_sel_rx == 0) ?
2 : conf->antenna_sel_tx - 1;
- priv->output_power = conf->power_level << 2;
+ priv->output_power = (conf->power_level << 2) & ~0x80;
ret = p54_set_freq(dev, cpu_to_le16(conf->channel->center_freq));
p54_set_vdcf(dev);
mutex_unlock(&priv->conf_mutex);
return ret;
}
+static void p54_beacon_tim(struct sk_buff *skb)
+{
+ /*
+ * the good excuse for this mess is ... the firmware.
+ * The dummy TIM MUST be at the end of the beacon frame,
+ * because it'll be overwritten!
+ */
+
+ struct ieee80211_mgmt *mgmt = (void *)skb->data;
+ u8 *pos, *end;
+
+ if (skb->len <= sizeof(mgmt))
+ return ;
+
+ pos = (u8 *)mgmt->u.beacon.variable;
+ end = skb->data + skb->len;
+ while (pos < end) {
+ if (pos + 2 + pos[1] > end) {
+ printk(KERN_ERR "p54: parsing beacon failed\n");
+ return;
+ }
+
+ if (pos[0] == WLAN_EID_TIM) {
+ u8 dtim_len = pos[1];
+ u8 *next = pos + 2 + dtim_len;
+
+ memmove(pos, next, end - next);
+
+ if (dtim_len > 3)
+ skb_trim(skb, skb->len - (dtim_len - 3));
+ if (dtim_len < 3)
+ skb_put(skb, skb->len + (3 - dtim_len));
+
+ pos = end - (dtim_len + 2);
+
+ /* add the dummy at the end */
+ pos[0] = WLAN_EID_TIM;
+ pos[1] = 3;
+ pos[2] = 0;
+ pos[3] = 1; /* FIX MAC80211: get the real dtim period
+ from the bss struct... */
+ pos[4] = 0;
+ return ;
+ }
+ pos += 2 + pos[1];
+ }
+}
+
+static int p54_beacon_update(struct ieee80211_hw *dev,
+ struct ieee80211_vif *vif)
+{
+ struct p54_common *priv = dev->priv;
+ struct sk_buff *beacon = ieee80211_beacon_get(dev, vif);
+
+ if (!beacon)
+ return -ENOMEM;
+
+ p54_beacon_tim(beacon);
+ p54_tx(dev, beacon);
+ priv->tsf_high32 = 0;
+ priv->tsf_low32 = 0;
+
+ return 0;
+}
+
static int p54_config_interface(struct ieee80211_hw *dev,
struct ieee80211_vif *vif,
struct ieee80211_if_conf *conf)
{
struct p54_common *priv = dev->priv;
+ int ret = 0;
- mutex_lock(&priv->conf_mutex);
- p54_set_filter(dev, 0, conf->bssid);
- p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0);
- memcpy(priv->bssid, conf->bssid, ETH_ALEN);
- mutex_unlock(&priv->conf_mutex);
- return 0;
+ switch (priv->mode) {
+ case IEEE80211_IF_TYPE_STA:
+ mutex_lock(&priv->conf_mutex);
+ memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+ p54_set_filter(dev, 0x1, conf->bssid);
+ p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0);
+ mutex_unlock(&priv->conf_mutex);
+ break;
+ case IEEE80211_IF_TYPE_AP:
+ case IEEE80211_IF_TYPE_IBSS:
+ mutex_lock(&priv->conf_mutex);
+ memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+ p54_set_freq(dev, dev->conf.channel->center_freq);
+ p54_set_filter(dev, priv->filter_type, priv->bssid);
+ mutex_unlock(&priv->conf_mutex);
+
+ if (conf->changed & IEEE80211_IFCC_BEACON) {
+ ret = p54_beacon_update(dev, vif);
+ if (ret)
+ return ret;
+
+ mutex_lock(&priv->conf_mutex);
+ p54_set_vdcf(dev);
+ mutex_unlock(&priv->conf_mutex);
+ }
+ break;
+ }
+
+ return ret;
}
static void p54_configure_filter(struct ieee80211_hw *dev,
@@ -1366,6 +1575,7 @@ static const struct ieee80211_ops p54_op
.config_interface = p54_config_interface,
.configure_filter = p54_configure_filter,
.conf_tx = p54_conf_tx,
+ .set_tim = p54_set_tim,
.get_stats = p54_get_stats,
.get_tx_stats = p54_get_tx_stats
};
diff -Nurp a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h
--- a/drivers/net/wireless/p54/p54common.h 2008-09-06 13:57:06.000000000 +0200
+++ b/drivers/net/wireless/p54/p54common.h 2008-09-07 01:55:21.000000000 +0200
@@ -321,4 +321,15 @@ struct p54_tx_control_xbow_synth {
u32 padding[5];
} __attribute__ ((packed));
+struct p54_tx_control_sta_unlock {
+ u8 addr[ETH_ALEN];
+ u16 padding;
+} __attribute__ ((packed));
+
+struct p54_tx_control_tim {
+ u8 count;
+ u8 unalloc0[3];
+ __le16 entry[8];
+} __attribute__ ((packed));
+
#endif /* P54COMMON_H */
On Wednesday 03 September 2008 01:14:12 Tomas Winkler wrote:
> > diff -Nurp a/drivers/net/wireless/p54/p54common.c
> > b/drivers/net/wireless/p54/p54common.c ---
> > a/drivers/net/wireless/p54/p54common.c 2008-09-01 22:25:35.000000000
> > +0200 +++ b/drivers/net/wireless/p54/p54common.c 2008-09-02
> > 21:29:47.000000000 +0200 @@ -93,7 +93,10 @@ int p54_parse_firmware(struct
> > ieee80211_
> > u32 code = le32_to_cpu(bootrec->code);
> > switch (code) {
> > case BR_CODE_COMPONENT_ID:
> > - switch (be32_to_cpu(*(__be32 *)bootrec->data)) {
> > + priv->fw_interface =
> > + be32_to_cpu(*(__be32 *)bootrec->data);
>
> what about be32_to_cpup?
> Tomas
whats the main difference between be32_to_cpu vs be32_to_cpus vs be32_to_cpup?
Does the extra p just stand for something like "pointer"?
hmm,
if yes, >>*<<(__be32 *)bootrec->data.
if no, please tell me more about it ;-).
Regards,
Chr
On Sunday 07 September 2008 02:32:56 Larry Finger wrote:
> Chr wrote:
> > On Sunday 07 September 2008 01:33:29 Larry Finger wrote:
> >> Chr wrote:
> >>> But, for newer firmwares you'll need "p54: better firmware support"
> >>> (cc4b0cbf4ab) as well. This changes were merged about 25-26 hours ago
> >>> into wireless-testing, the only thing that isn't in yet is 802.11a
> >>> support....
> >>>
> >>> the LM87 firmware is this one:
> >>> http://daemonizer.de/prism54/prism54-fw/fw-usb/2.13.1.0.arm.1
> >>>
> >>> This link can be found on the driver's site too:
> >>> http://linuxwireless.org/en/users/Drivers/p54
> >>
> >> Thanks. That one fixed the ping problem. I had the latest
> >> wireless-testing, and have added the patches you posted earlier today.
> >
> > Well, since you already do some testing here. Want more? ;-)
> >
> > I will be off for about 4-5 weeks and it would be very nice if someone
> > with lots of broadcom hardware can test if the p54 works ADHOC & AP mode
> > with them.
> >
> > i've already (successfully) tested Intel's 2915 & 4965, several atheros
> > chipsets and another prism54 on different operating systems.
> >
> > But there could be problems with some broadcom chips.
>
> I'll see what I can do.
>
> After loading the new firmware, p54usb crapped out after the following
> message was logged:
>
> phy9: not handling 0x02 type control frame
>
> After this, I had to unload and reload the driver. I have not yet had
> time to check on it.
>
Do you have a big-endian machine by accident?
Anyway control flags with 0x02 is some sort of scanning trap...
These packages can be produces easily by setting chan->flags = 2 (or 4,6?)
and setting the dwell timers as well in p54_set_freq.
Since we don't do this, is there any chance you can hexdump
the unknown/corrupted frames?
and as a last shot: try another firmware, maybe this one works better for you.
Regards,
Chr
On Sunday 07 September 2008 00:57:35 Larry Finger wrote:
> Christian Lamparter wrote:
> > This patch adds the necessary changes to support LM87 firmwares.
>
> Do you have a URL for the LM87 firmware? After this patch was added, I
> tried the 2.5.11.0.arm and 2.13.1.0.arm files, but only the old
> 2.5.8.0 works. That is the one with the 'ping -s 1400' problem.
>
Yes
But, for newer firmwares you'll need "p54: better firmware support" (cc4b0cbf4ab)
as well. This changes were merged about 25-26 hours ago into wireless-testing,
the only thing that isn't in yet is 802.11a support....
the LM87 firmware is this one:
http://daemonizer.de/prism54/prism54-fw/fw-usb/2.13.1.0.arm.1
This link can be found on the driver's site too:
http://linuxwireless.org/en/users/Drivers/p54
Regards,
Chr
Chr wrote:
> On Sunday 07 September 2008 01:33:29 Larry Finger wrote:
>> Chr wrote:
>>> But, for newer firmwares you'll need "p54: better firmware support"
>>> (cc4b0cbf4ab) as well. This changes were merged about 25-26 hours ago
>>> into wireless-testing, the only thing that isn't in yet is 802.11a
>>> support....
>>>
>>> the LM87 firmware is this one:
>>> http://daemonizer.de/prism54/prism54-fw/fw-usb/2.13.1.0.arm.1
>>>
>>> This link can be found on the driver's site too:
>>> http://linuxwireless.org/en/users/Drivers/p54
>> Thanks. That one fixed the ping problem. I had the latest
>> wireless-testing, and have added the patches you posted earlier today.
>>
> Well, since you already do some testing here. Want more? ;-)
>
> I will be off for about 4-5 weeks and it would be very nice if someone with lots of broadcom
> hardware can test if the p54 works ADHOC & AP mode with them.
>
> i've already (successfully) tested Intel's 2915 & 4965, several atheros chipsets and another prism54
> on different operating systems.
>
> But there could be problems with some broadcom chips.
I'll see what I can do.
After loading the new firmware, p54usb crapped out after the following
message was logged:
phy9: not handling 0x02 type control frame
After this, I had to unload and reload the driver. I have not yet had
time to check on it.
Larry
This patch adds the necessary changes to support LM87 firmwares.
Signed-off-by: Christian Lamparter <[email protected]>
---
as you can see, the *(__be32 *) cast is now gone ;-)
---
diff -Nurp a/drivers/net/wireless/p54/p54common.c
b/drivers/net/wireless/p54/p54common.c
--- a/drivers/net/wireless/p54/p54common.c 2008-09-01 22:25:35.000000000 +0200
+++ b/drivers/net/wireless/p54/p54common.c 2008-09-04 12:02:51.000000000 +0200
@@ -93,7 +93,8 @@ int p54_parse_firmware(struct ieee80211_
u32 code = le32_to_cpu(bootrec->code);
switch (code) {
case BR_CODE_COMPONENT_ID:
- switch (be32_to_cpu(*(__be32 *)bootrec->data)) {
+ priv->fw_interface = be32_to_cpup(bootrec->data);
+ switch (priv->fw_interface) {
case FW_FMAC:
printk(KERN_INFO "p54: FreeMAC firmware\n");
break;
@@ -104,7 +105,7 @@ int p54_parse_firmware(struct ieee80211_
printk(KERN_INFO "p54: LM86 firmware\n");
break;
case FW_LM87:
- printk(KERN_INFO "p54: LM87 firmware - not supported yet!\n");
+ printk(KERN_INFO "p54: LM87 firmware\n");
break;
default:
printk(KERN_INFO "p54: unknown firmware\n");
diff -Nurp a/drivers/net/wireless/p54/p54common.h
b/drivers/net/wireless/p54/p54common.h
--- a/drivers/net/wireless/p54/p54common.h 2008-09-01 01:56:53.000000000 +0200
+++ b/drivers/net/wireless/p54/p54common.h 2008-09-02 19:39:10.000000000 +0200
@@ -50,11 +50,6 @@ struct bootrec_desc {
#define BR_CODE_END_OF_BRA 0xFF0000FF
#define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF
-#define FW_FMAC 0x464d4143
-#define FW_LM86 0x4c4d3836
-#define FW_LM87 0x4c4d3837
-#define FW_LM20 0x4c4d3230
-
/* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from
islsm_pda.h) */
struct pda_entry {
diff -Nurp a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h
--- a/drivers/net/wireless/p54/p54.h 2008-09-01 02:20:25.000000000 +0200
+++ b/drivers/net/wireless/p54/p54.h 2008-09-02 19:39:26.000000000 +0200
@@ -42,6 +42,11 @@ struct p54_control_hdr {
#define ISL38XX_DEV_FIRMWARE_ADDR 0x20000
+#define FW_FMAC 0x464d4143
+#define FW_LM86 0x4c4d3836
+#define FW_LM87 0x4c4d3837
+#define FW_LM20 0x4c4d3230
+
struct p54_common {
u32 rx_start;
u32 rx_end;
@@ -68,6 +73,7 @@ struct p54_common {
unsigned int tx_hdr_len;
void *cached_vdcf;
unsigned int fw_var;
+ unsigned int fw_interface;
struct ieee80211_tx_queue_stats tx_stats[8];
void *eeprom;
struct completion eeprom_comp;
diff -Nurp a/drivers/net/wireless/p54/p54usb.c
b/drivers/net/wireless/p54/p54usb.c
--- a/drivers/net/wireless/p54/p54usb.c 2008-09-01 22:23:46.000000000 +0200
+++ b/drivers/net/wireless/p54/p54usb.c 2008-09-02 21:28:36.000000000 +0200
@@ -91,8 +91,13 @@ static void p54u_rx_cb(struct urb *urb)
skb_unlink(skb, &priv->rx_queue);
skb_put(skb, urb->actual_length);
- if (!priv->hw_type)
- skb_pull(skb, sizeof(struct net2280_tx_hdr));
+
+ if (priv->hw_type == P54U_NET2280)
+ skb_pull(skb, priv->common.tx_hdr_len);
+ if (priv->common.fw_interface == FW_LM87) {
+ skb_pull(skb, 4);
+ skb_put(skb, 4);
+ }
if (p54_rx(dev, skb)) {
skb = dev_alloc_skb(priv->common.rx_mtu + 32);
@@ -109,9 +114,12 @@ static void p54u_rx_cb(struct urb *urb)
urb->context = skb;
skb_queue_tail(&priv->rx_queue, skb);
} else {
- if (!priv->hw_type)
- skb_push(skb, sizeof(struct net2280_tx_hdr));
-
+ if (priv->hw_type == P54U_NET2280)
+ skb_push(skb, priv->common.tx_hdr_len);
+ if (priv->common.fw_interface == FW_LM87) {
+ skb_push(skb, 4);
+ skb_put(skb, 4);
+ }
skb_reset_tail_pointer(skb);
skb_trim(skb, 0);
if (urb->transfer_buffer != skb_tail_pointer(skb)) {
@@ -210,6 +218,42 @@ static void p54u_tx_3887(struct ieee8021
usb_submit_urb(data_urb, GFP_ATOMIC);
}
+__le32 p54u_lm87_chksum(const u32 *data, size_t length)
+{
+ __le32 chk = 0;
+
+ length >>= 2;
+ while (length--) {
+ chk ^= cpu_to_le32(*data++);
+ chk = (chk >> 5) ^ (chk << 3);
+ }
+
+ return chk;
+}
+
+static void p54u_tx_lm87(struct ieee80211_hw *dev,
+ struct p54_control_hdr *data,
+ size_t len, int free_on_tx)
+{
+ struct p54u_priv *priv = dev->priv;
+ struct urb *data_urb;
+ struct lm87_tx_hdr *hdr = (void *)data - sizeof(*hdr);
+
+ data_urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!data_urb)
+ return;
+
+ hdr->chksum = p54u_lm87_chksum((u32 *)data, len);
+ hdr->device_addr = data->req_id;
+
+ usb_fill_bulk_urb(data_urb, priv->udev,
+ usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), hdr,
+ len + sizeof(*hdr), free_on_tx ? p54u_tx_free_cb : p54u_tx_cb,
+ dev);
+
+ usb_submit_urb(data_urb, GFP_ATOMIC);
+}
+
static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr
*data,
size_t len, int free_on_tx)
{
@@ -776,21 +820,23 @@ static int __devinit p54u_probe(struct u
}
}
priv->common.open = p54u_open;
-
+ priv->common.stop = p54u_stop;
if (recognized_pipes < P54U_PIPE_NUMBER) {
priv->hw_type = P54U_3887;
- priv->common.tx = p54u_tx_3887;
+ err = p54u_upload_firmware_3887(dev);
+ if (priv->common.fw_interface == FW_LM87) {
+ dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
+ priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
+ priv->common.tx = p54u_tx_lm87;
+ } else
+ priv->common.tx = p54u_tx_3887;
} else {
+ priv->hw_type = P54U_NET2280;
dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
priv->common.tx = p54u_tx_net2280;
- }
- priv->common.stop = p54u_stop;
-
- if (priv->hw_type)
- err = p54u_upload_firmware_3887(dev);
- else
err = p54u_upload_firmware_net2280(dev);
+ }
if (err)
goto err_free_dev;
diff -Nurp a/drivers/net/wireless/p54/p54usb.h
b/drivers/net/wireless/p54/p54usb.h
--- a/drivers/net/wireless/p54/p54usb.h 2008-09-01 01:56:53.000000000 +0200
+++ b/drivers/net/wireless/p54/p54usb.h 2008-09-02 19:23:52.000000000 +0200
@@ -72,6 +72,11 @@ struct net2280_tx_hdr {
u8 padding[8];
} __attribute__((packed));
+struct lm87_tx_hdr {
+ __le32 device_addr;
+ __le32 chksum;
+} __attribute__((packed));
+
/* Some flags for the isl hardware registers controlling DMA inside the
* chip */
#define ISL38XX_DMA_STATUS_DONE 0x00000001
Christian Lamparter wrote:
> This patch adds the necessary changes to support LM87 firmwares.
>
Do you have a URL for the LM87 firmware? After this patch was added, I
tried the 2.5.11.0.arm and 2.13.1.0.arm files, but only the old
2.5.8.0 works. That is the one with the 'ping -s 1400' problem.
Larry
Chr wrote:
> But, for newer firmwares you'll need "p54: better firmware support" (cc4b0cbf4ab)
> as well. This changes were merged about 25-26 hours ago into wireless-testing,
> the only thing that isn't in yet is 802.11a support....
>
> the LM87 firmware is this one:
> http://daemonizer.de/prism54/prism54-fw/fw-usb/2.13.1.0.arm.1
>
> This link can be found on the driver's site too:
> http://linuxwireless.org/en/users/Drivers/p54
Thanks. That one fixed the ping problem. I had the latest
wireless-testing, and have added the patches you posted earlier today.
Thanks,
Larry