linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] p54usb: support LM87 firmwares
@ 2008-09-02 19:39 Christian Lamparter
  2008-09-02 23:14 ` Tomas Winkler
  0 siblings, 1 reply; 11+ messages in thread
From: Christian Lamparter @ 2008-09-02 19:39 UTC (permalink / raw)
  To: linux-wireless; +Cc: John W Linville, Larry Finger

This patch adds the necessary changes to support LM87 firmwares.

Signed-off-by: Christian Lamparter <chunkeey@web.de>
---
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


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] p54usb: support LM87 firmwares
  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
  0 siblings, 1 reply; 11+ messages in thread
From: Tomas Winkler @ 2008-09-02 23:14 UTC (permalink / raw)
  To: Christian Lamparter; +Cc: linux-wireless, John W Linville, Larry Finger

On Tue, Sep 2, 2008 at 10:39 PM, Christian Lamparter <chunkeey@web.de> wrote:
> This patch adds the necessary changes to support LM87 firmwares.
>
> Signed-off-by: Christian Lamparter <chunkeey@web.de>
> ---
> 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

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] p54usb: support LM87 firmwares
  2008-09-02 23:14 ` Tomas Winkler
@ 2008-09-03  0:00   ` Christian Lamparter
  2008-09-04  1:44     ` Pavel Roskin
  0 siblings, 1 reply; 11+ messages in thread
From: Christian Lamparter @ 2008-09-03  0:00 UTC (permalink / raw)
  To: Tomas Winkler; +Cc: linux-wireless, John W Linville, Larry Finger

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

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] p54usb: support LM87 firmwares
  2008-09-03  0:00   ` Christian Lamparter
@ 2008-09-04  1:44     ` Pavel Roskin
  2008-09-04 10:29       ` [PATCH v2] " Christian Lamparter
  0 siblings, 1 reply; 11+ messages in thread
From: Pavel Roskin @ 2008-09-04  1:44 UTC (permalink / raw)
  To: Christian Lamparter
  Cc: Tomas Winkler, linux-wireless, John W Linville, Larry Finger

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

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v2] p54usb: support LM87 firmwares
  2008-09-04  1:44     ` Pavel Roskin
@ 2008-09-04 10:29       ` Christian Lamparter
  2008-09-06 22:57         ` Larry Finger
  0 siblings, 1 reply; 11+ messages in thread
From: Christian Lamparter @ 2008-09-04 10:29 UTC (permalink / raw)
  To: linux-wireless; +Cc: John W Linville, Pavel Roskin, Larry Finger, Tomas Winkler


This patch adds the necessary changes to support LM87 firmwares.

Signed-off-by: Christian Lamparter <chunkeey@web.de>
---
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



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] p54usb: support LM87 firmwares
  2008-09-04 10:29       ` [PATCH v2] " Christian Lamparter
@ 2008-09-06 22:57         ` Larry Finger
  2008-09-06 23:19           ` Chr
  0 siblings, 1 reply; 11+ messages in thread
From: Larry Finger @ 2008-09-06 22:57 UTC (permalink / raw)
  To: Christian Lamparter
  Cc: linux-wireless, John W Linville, Pavel Roskin, Tomas Winkler

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


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] p54usb: support LM87 firmwares
  2008-09-06 22:57         ` Larry Finger
@ 2008-09-06 23:19           ` Chr
  2008-09-06 23:33             ` Larry Finger
  0 siblings, 1 reply; 11+ messages in thread
From: Chr @ 2008-09-06 23:19 UTC (permalink / raw)
  To: Larry Finger; +Cc: linux-wireless, John W Linville, Pavel Roskin, Tomas Winkler

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

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] p54usb: support LM87 firmwares
  2008-09-06 23:19           ` Chr
@ 2008-09-06 23:33             ` Larry Finger
  2008-09-07  0:25               ` Chr
  0 siblings, 1 reply; 11+ messages in thread
From: Larry Finger @ 2008-09-06 23:33 UTC (permalink / raw)
  To: Chr; +Cc: linux-wireless, John W Linville, Pavel Roskin, Tomas Winkler

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


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] p54usb: support LM87 firmwares
  2008-09-06 23:33             ` Larry Finger
@ 2008-09-07  0:25               ` Chr
  2008-09-07  0:32                 ` Larry Finger
  0 siblings, 1 reply; 11+ messages in thread
From: Chr @ 2008-09-07  0:25 UTC (permalink / raw)
  To: linux-wireless; +Cc: Larry Finger, John W Linville, Pavel Roskin, Tomas Winkler

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


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] p54usb: support LM87 firmwares
  2008-09-07  0:25               ` Chr
@ 2008-09-07  0:32                 ` Larry Finger
  2008-09-07  0:56                   ` Christian Lamparter
  0 siblings, 1 reply; 11+ messages in thread
From: Larry Finger @ 2008-09-07  0:32 UTC (permalink / raw)
  To: Chr; +Cc: linux-wireless, John W Linville, Pavel Roskin, Tomas Winkler

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



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] p54usb: support LM87 firmwares
  2008-09-07  0:32                 ` Larry Finger
@ 2008-09-07  0:56                   ` Christian Lamparter
  0 siblings, 0 replies; 11+ messages in thread
From: Christian Lamparter @ 2008-09-07  0:56 UTC (permalink / raw)
  To: Larry Finger; +Cc: linux-wireless, John W Linville, Pavel Roskin, Tomas Winkler

[-- Attachment #1: Type: text/plain, Size: 1903 bytes --]

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

[-- Attachment #2: 2.13.3.lm87.arm --]
[-- Type: application/octet-stream, Size: 29092 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2008-09-07  0:53 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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
2008-09-07  0:32                 ` Larry Finger
2008-09-07  0:56                   ` Christian Lamparter

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).