All of lore.kernel.org
 help / color / mirror / Atom feed
From: Chr <chunkeey@web.de>
To: linux-wireless@vger.kernel.org
Cc: Larry Finger <Larry.Finger@lwfinger.net>,
	John W Linville <linville@tuxdriver.com>,
	Pavel Roskin <proski@gnu.org>, Tomas Winkler <tomasw@gmail.com>
Subject: Re: [PATCH v2] p54usb: support LM87 firmwares
Date: Sun, 7 Sep 2008 02:25:40 +0200	[thread overview]
Message-ID: <200809070225.41177.chunkeey@web.de> (raw)
In-Reply-To: <48C31349.7060401@lwfinger.net>

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 */


  reply	other threads:[~2008-09-07  0:22 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-09-02 19:39 [PATCH] p54usb: support LM87 firmwares Christian Lamparter
2008-09-02 23:14 ` Tomas Winkler
2008-09-03  0:00   ` Christian Lamparter
2008-09-04  1:44     ` Pavel Roskin
2008-09-04 10:29       ` [PATCH v2] " Christian Lamparter
2008-09-06 22:57         ` Larry Finger
2008-09-06 23:19           ` Chr
2008-09-06 23:33             ` Larry Finger
2008-09-07  0:25               ` Chr [this message]
2008-09-07  0:32                 ` Larry Finger
2008-09-07  0:56                   ` Christian Lamparter

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=200809070225.41177.chunkeey@web.de \
    --to=chunkeey@web.de \
    --cc=Larry.Finger@lwfinger.net \
    --cc=linux-wireless@vger.kernel.org \
    --cc=linville@tuxdriver.com \
    --cc=proski@gnu.org \
    --cc=tomasw@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.