qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Grant Likely <grant.likely@secretlab.ca>
To: qemu-devel@nongnu.org
Cc: Grant Likely <grant.likely@secretlab.ca>,
	Peter Maydell <peter.maydell@linaro.org>,
	Anthony Liguori <aliguori@us.ibm.com>,
	Paul Brook <paul@codesourcery.com>,
	"Edgar E. Iglesias" <edgar.iglesias@gmail.com>
Subject: [Qemu-devel] [PATCH 1/3] net/bitbang_mdio: Generalize etraxfs MDIO bitbanging emulation
Date: Sat, 19 Jan 2013 18:28:10 -0400	[thread overview]
Message-ID: <1358634492-22627-2-git-send-email-grant.likely@secretlab.ca> (raw)
In-Reply-To: <1358634492-22627-1-git-send-email-grant.likely@secretlab.ca>

The etraxfs Ethernet model implements quite a nice bitbanging core. The
change splits it out into a separate .c file. There are no functional
changes here, just movement of code and reformatting to match qemu
coding standards.

Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Paul Brook <paul@codesourcery.com>
Cc: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Cc: Anthony Liguori <aliguori@us.ibm.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---
 hw/bitbang_mdio.c     |  263 +++++++++++++++++++++++++++++++++++++++++++++++
 hw/bitbang_mdio.h     |   72 +++++++++++++
 hw/cris/Makefile.objs |    1 +
 hw/etraxfs_eth.c      |  273 +------------------------------------------------
 4 files changed, 337 insertions(+), 272 deletions(-)
 create mode 100644 hw/bitbang_mdio.c
 create mode 100644 hw/bitbang_mdio.h

diff --git a/hw/bitbang_mdio.c b/hw/bitbang_mdio.c
new file mode 100644
index 0000000..f0ee6af
--- /dev/null
+++ b/hw/bitbang_mdio.c
@@ -0,0 +1,263 @@
+/*
+ * QEMU Bitbang Ethernet MDIO bus & PHY controllers.
+ *
+ * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include "qemu-common.h"
+#include "qemu/log.h"
+#include "bitbang_mdio.h"
+
+#define D(x)
+
+/* Advertisement control register. */
+#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
+#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
+#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
+#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
+
+/*
+ * The MDIO extensions in the TDK PHY model were reversed engineered from the
+ * linux driver (PHYID and Diagnostics reg).
+ * TODO: Add friendly names for the register nums.
+ */
+static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req)
+{
+    int regnum;
+    unsigned r = 0;
+
+    regnum = req & 0x1f;
+
+    switch (regnum) {
+    case 1:
+        if (!phy->link) {
+            break;
+        }
+        /* MR1.     */
+        /* Speeds and modes.  */
+        r |= (1 << 13) | (1 << 14);
+        r |= (1 << 11) | (1 << 12);
+        r |= (1 << 5); /* Autoneg complete.  */
+        r |= (1 << 3); /* Autoneg able.     */
+        r |= (1 << 2); /* link.     */
+        break;
+    case 5:
+        /* Link partner ability.
+           We are kind; always agree with whatever best mode
+           the guest advertises.  */
+        r = 1 << 14; /* Success.  */
+        /* Copy advertised modes.  */
+        r |= phy->regs[4] & (15 << 5);
+        /* Autoneg support.  */
+        r |= 1;
+        break;
+    case 18:
+    {
+        /* Diagnostics reg.  */
+        int duplex = 0;
+        int speed_100 = 0;
+
+        if (!phy->link) {
+            break;
+        }
+
+        /* Are we advertising 100 half or 100 duplex ? */
+        speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
+        speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
+
+        /* Are we advertising 10 duplex or 100 duplex ? */
+        duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
+        duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
+        r = (speed_100 << 10) | (duplex << 11);
+    }
+    break;
+
+    default:
+        r = phy->regs[regnum];
+        break;
+    }
+    D(printf("\n%s %x = reg[%d]\n", __func__, r, regnum));
+    return r;
+}
+
+static void tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data)
+{
+    int regnum;
+
+    regnum = req & 0x1f;
+    D(printf("%s reg[%d] = %x\n", __func__, regnum, data));
+    switch (regnum) {
+    default:
+        phy->regs[regnum] = data;
+        break;
+    }
+}
+
+void tdk_init(struct qemu_phy *phy)
+{
+    phy->regs[0] = 0x3100;
+    /* PHY Id. */
+    phy->regs[2] = 0x0300;
+    phy->regs[3] = 0xe400;
+    /* Autonegotiation advertisement reg. */
+    phy->regs[4] = 0x01e1;
+    phy->link = 1;
+
+    phy->read = tdk_read;
+    phy->write = tdk_write;
+}
+
+void mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
+{
+    bus->devs[addr & 0x1f] = phy;
+}
+
+#ifdef USE_THIS_DEAD_CODE
+void mdio_detach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
+{
+    bus->devs[addr & 0x1f] = NULL;
+}
+#endif
+
+void mdio_read_req(struct qemu_mdio *bus)
+{
+    struct qemu_phy *phy;
+
+    phy = bus->devs[bus->addr];
+    if (phy && phy->read) {
+        bus->data = phy->read(phy, bus->req);
+    } else {
+        bus->data = 0xffff;
+    }
+    D(qemu_log("%s addr=%d reg=%d data=%x\n", __func__,
+               bus->addr, bus->req, bus->data));
+}
+
+void mdio_write_req(struct qemu_mdio *bus)
+{
+    struct qemu_phy *phy;
+
+    phy = bus->devs[bus->addr];
+    if (phy && phy->write) {
+        phy->write(phy, bus->req, bus->data);
+    }
+}
+
+void mdio_cycle(struct qemu_mdio *bus)
+{
+    bus->cnt++;
+
+    D(printf("mdc=%d mdio=%d state=%d cnt=%d drv=%d\n",
+             bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive));
+    switch (bus->state) {
+    case PREAMBLE:
+        if (bus->mdc) {
+            if (bus->cnt >= (32 * 2) && !bus->mdio) {
+                bus->cnt = 0;
+                bus->state = SOF;
+                bus->data = 0;
+            }
+        }
+        break;
+    case SOF:
+        if (bus->mdc) {
+            if (bus->mdio != 1) {
+                printf("WARNING: no SOF\n");
+            }
+            if (bus->cnt == 1*2) {
+                bus->cnt = 0;
+                bus->opc = 0;
+                bus->state = OPC;
+            }
+        }
+        break;
+    case OPC:
+        if (bus->mdc) {
+            bus->opc <<= 1;
+            bus->opc |= bus->mdio & 1;
+            if (bus->cnt == 2*2) {
+                bus->cnt = 0;
+                bus->addr = 0;
+                bus->state = ADDR;
+            }
+        }
+        break;
+    case ADDR:
+        if (bus->mdc) {
+            bus->addr <<= 1;
+            bus->addr |= bus->mdio & 1;
+
+            if (bus->cnt == 5*2) {
+                bus->cnt = 0;
+                bus->req = 0;
+                bus->state = REQ;
+            }
+        }
+        break;
+    case REQ:
+        if (bus->mdc) {
+            bus->req <<= 1;
+            bus->req |= bus->mdio & 1;
+            if (bus->cnt == 5*2) {
+                bus->cnt = 0;
+                bus->state = TURNAROUND;
+            }
+        }
+        break;
+    case TURNAROUND:
+        if (bus->mdc && bus->cnt == 2*2) {
+            bus->mdio = 0;
+            bus->cnt = 0;
+
+            if (bus->opc == 2) {
+                bus->drive = 1;
+                mdio_read_req(bus);
+                bus->mdio = bus->data & 1;
+            }
+            bus->state = DATA;
+        }
+        break;
+    case DATA:
+        if (!bus->mdc) {
+            if (bus->drive) {
+                bus->mdio = !!(bus->data & (1 << 15));
+                bus->data <<= 1;
+            }
+        } else {
+            if (!bus->drive) {
+                bus->data <<= 1;
+                bus->data |= bus->mdio;
+            }
+            if (bus->cnt == 16 * 2) {
+                bus->cnt = 0;
+                bus->state = PREAMBLE;
+                if (!bus->drive) {
+                    mdio_write_req(bus);
+                }
+                bus->drive = 0;
+            }
+        }
+        break;
+    default:
+        break;
+    }
+}
diff --git a/hw/bitbang_mdio.h b/hw/bitbang_mdio.h
new file mode 100644
index 0000000..3484aba
--- /dev/null
+++ b/hw/bitbang_mdio.h
@@ -0,0 +1,72 @@
+#ifndef BITBANG_MDIO_H
+#define BITBANG_MDIO_H
+
+/*
+ * QEMU Bitbang Ethernet MDIO bus & PHY controllers.
+ *
+ * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+struct qemu_phy {
+    uint32_t regs[32];
+
+    int link;
+
+    unsigned int (*read)(struct qemu_phy *phy, unsigned int req);
+    void (*write)(struct qemu_phy *phy, unsigned int req, unsigned int data);
+};
+
+struct qemu_mdio {
+    /* bus. */
+    int mdc;
+    int mdio;
+
+    /* decoder.  */
+    enum {
+        PREAMBLE,
+        SOF,
+        OPC,
+        ADDR,
+        REQ,
+        TURNAROUND,
+        DATA
+    } state;
+    unsigned int drive;
+
+    unsigned int cnt;
+    unsigned int addr;
+    unsigned int opc;
+    unsigned int req;
+    unsigned int data;
+
+    struct qemu_phy *devs[32];
+};
+
+void tdk_init(struct qemu_phy *phy);
+void mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy,
+                 unsigned int addr);
+void mdio_read_req(struct qemu_mdio *bus);
+void mdio_write_req(struct qemu_mdio *bus);
+void mdio_cycle(struct qemu_mdio *bus);
+
+#endif
diff --git a/hw/cris/Makefile.objs b/hw/cris/Makefile.objs
index aa9298a..86759a3 100644
--- a/hw/cris/Makefile.objs
+++ b/hw/cris/Makefile.objs
@@ -9,5 +9,6 @@ obj-y += etraxfs_pic.o
 obj-y += etraxfs_eth.o
 obj-y += etraxfs_timer.o
 obj-y += etraxfs_ser.o
+obj-y += bitbang_mdio.o
 
 obj-y := $(addprefix ../,$(obj-y))
diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c
index ec23fa6..67b4797 100644
--- a/hw/etraxfs_eth.c
+++ b/hw/etraxfs_eth.c
@@ -26,281 +26,10 @@
 #include "sysbus.h"
 #include "net/net.h"
 #include "etraxfs.h"
+#include "bitbang_mdio.h"
 
 #define D(x)
 
-/* Advertisement control register. */
-#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
-#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
-#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
-#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
-
-/* 
- * The MDIO extensions in the TDK PHY model were reversed engineered from the 
- * linux driver (PHYID and Diagnostics reg).
- * TODO: Add friendly names for the register nums.
- */
-struct qemu_phy
-{
-	uint32_t regs[32];
-
-	int link;
-
-	unsigned int (*read)(struct qemu_phy *phy, unsigned int req);
-	void (*write)(struct qemu_phy *phy, unsigned int req, 
-		      unsigned int data);
-};
-
-static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req)
-{
-	int regnum;
-	unsigned r = 0;
-
-	regnum = req & 0x1f;
-
-	switch (regnum) {
-		case 1:
-			if (!phy->link)
-				break;
-			/* MR1.	 */
-			/* Speeds and modes.  */
-			r |= (1 << 13) | (1 << 14);
-			r |= (1 << 11) | (1 << 12);
-			r |= (1 << 5); /* Autoneg complete.  */
-			r |= (1 << 3); /* Autoneg able.	 */
-			r |= (1 << 2); /* link.	 */
-			break;
-		case 5:
-			/* Link partner ability.
-			   We are kind; always agree with whatever best mode
-			   the guest advertises.  */
-			r = 1 << 14; /* Success.  */
-			/* Copy advertised modes.  */
-			r |= phy->regs[4] & (15 << 5);
-			/* Autoneg support.  */
-			r |= 1;
-			break;
-		case 18:
-		{
-			/* Diagnostics reg.  */
-			int duplex = 0;
-			int speed_100 = 0;
-
-			if (!phy->link)
-				break;
-
-			/* Are we advertising 100 half or 100 duplex ? */
-			speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
-			speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
-
-			/* Are we advertising 10 duplex or 100 duplex ? */
-			duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
-			duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
-			r = (speed_100 << 10) | (duplex << 11);
-		}
-		break;
-
-		default:
-			r = phy->regs[regnum];
-			break;
-	}
-	D(printf("\n%s %x = reg[%d]\n", __func__, r, regnum));
-	return r;
-}
-
-static void 
-tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data)
-{
-	int regnum;
-
-	regnum = req & 0x1f;
-	D(printf("%s reg[%d] = %x\n", __func__, regnum, data));
-	switch (regnum) {
-		default:
-			phy->regs[regnum] = data;
-			break;
-	}
-}
-
-static void 
-tdk_init(struct qemu_phy *phy)
-{
-	phy->regs[0] = 0x3100;
-	/* PHY Id.  */
-	phy->regs[2] = 0x0300;
-	phy->regs[3] = 0xe400;
-	/* Autonegotiation advertisement reg.  */
-	phy->regs[4] = 0x01E1;
-	phy->link = 1;
-
-	phy->read = tdk_read;
-	phy->write = tdk_write;
-}
-
-struct qemu_mdio
-{
-	/* bus.	 */
-	int mdc;
-	int mdio;
-
-	/* decoder.  */
-	enum {
-		PREAMBLE,
-		SOF,
-		OPC,
-		ADDR,
-		REQ,
-		TURNAROUND,
-		DATA
-	} state;
-	unsigned int drive;
-
-	unsigned int cnt;
-	unsigned int addr;
-	unsigned int opc;
-	unsigned int req;
-	unsigned int data;
-
-	struct qemu_phy *devs[32];
-};
-
-static void 
-mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
-{
-	bus->devs[addr & 0x1f] = phy;
-}
-
-#ifdef USE_THIS_DEAD_CODE
-static void 
-mdio_detach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
-{
-	bus->devs[addr & 0x1f] = NULL;	
-}
-#endif
-
-static void mdio_read_req(struct qemu_mdio *bus)
-{
-	struct qemu_phy *phy;
-
-	phy = bus->devs[bus->addr];
-	if (phy && phy->read)
-		bus->data = phy->read(phy, bus->req);
-	else 
-		bus->data = 0xffff;
-}
-
-static void mdio_write_req(struct qemu_mdio *bus)
-{
-	struct qemu_phy *phy;
-
-	phy = bus->devs[bus->addr];
-	if (phy && phy->write)
-		phy->write(phy, bus->req, bus->data);
-}
-
-static void mdio_cycle(struct qemu_mdio *bus)
-{
-	bus->cnt++;
-
-	D(printf("mdc=%d mdio=%d state=%d cnt=%d drv=%d\n",
-		bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive));
-#if 0
-	if (bus->mdc)
-		printf("%d", bus->mdio);
-#endif
-	switch (bus->state)
-	{
-		case PREAMBLE:
-			if (bus->mdc) {
-				if (bus->cnt >= (32 * 2) && !bus->mdio) {
-					bus->cnt = 0;
-					bus->state = SOF;
-					bus->data = 0;
-				}
-			}
-			break;
-		case SOF:
-			if (bus->mdc) {
-				if (bus->mdio != 1)
-					printf("WARNING: no SOF\n");
-				if (bus->cnt == 1*2) {
-					bus->cnt = 0;
-					bus->opc = 0;
-					bus->state = OPC;
-				}
-			}
-			break;
-		case OPC:
-			if (bus->mdc) {
-				bus->opc <<= 1;
-				bus->opc |= bus->mdio & 1;
-				if (bus->cnt == 2*2) {
-					bus->cnt = 0;
-					bus->addr = 0;
-					bus->state = ADDR;
-				}
-			}
-			break;
-		case ADDR:
-			if (bus->mdc) {
-				bus->addr <<= 1;
-				bus->addr |= bus->mdio & 1;
-
-				if (bus->cnt == 5*2) {
-					bus->cnt = 0;
-					bus->req = 0;
-					bus->state = REQ;
-				}
-			}
-			break;
-		case REQ:
-			if (bus->mdc) {
-				bus->req <<= 1;
-				bus->req |= bus->mdio & 1;
-				if (bus->cnt == 5*2) {
-					bus->cnt = 0;
-					bus->state = TURNAROUND;
-				}
-			}
-			break;
-		case TURNAROUND:
-			if (bus->mdc && bus->cnt == 2*2) {
-				bus->mdio = 0;
-				bus->cnt = 0;
-
-				if (bus->opc == 2) {
-					bus->drive = 1;
-					mdio_read_req(bus);
-					bus->mdio = bus->data & 1;
-				}
-				bus->state = DATA;
-			}
-			break;
-		case DATA:			
-			if (!bus->mdc) {
-				if (bus->drive) {
-					bus->mdio = !!(bus->data & (1 << 15));
-					bus->data <<= 1;
-				}
-			} else {
-				if (!bus->drive) {
-					bus->data <<= 1;
-					bus->data |= bus->mdio;
-				}
-				if (bus->cnt == 16 * 2) {
-					bus->cnt = 0;
-					bus->state = PREAMBLE;
-					if (!bus->drive)
-						mdio_write_req(bus);
-					bus->drive = 0;
-				}
-			}
-			break;
-		default:
-			break;
-	}
-}
-
 /* ETRAX-FS Ethernet MAC block starts here.  */
 
 #define RW_MA0_LO	  0x00
-- 
1.7.10.4

  reply	other threads:[~2013-01-20  0:20 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-01-19 22:28 [Qemu-devel] [PATCH 0/3] Generalize bitbang MDIO and use for versatile-pb Grant Likely
2013-01-19 22:28 ` Grant Likely [this message]
2013-01-20 17:29   ` [Qemu-devel] [PATCH 1/3] net/bitbang_mdio: Generalize etraxfs MDIO bitbanging emulation Andreas Färber
2013-01-21 12:51   ` Edgar E. Iglesias
2013-01-19 22:28 ` [Qemu-devel] [PATCH 2/3] net/bitbang_mdio: Never set PHY RST and ANEG_RST bits on register write Grant Likely
2013-01-19 22:28 ` [Qemu-devel] [PATCH 3/3] net/bitbang_mdio: Use bitbang core for smc91c111 network device Grant Likely
2013-01-20 11:29   ` Peter Maydell
2013-01-21 13:12     ` Grant Likely
2013-01-20 17:26 ` [Qemu-devel] [PATCH 0/3] Generalize bitbang MDIO and use for versatile-pb Andreas Färber

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=1358634492-22627-2-git-send-email-grant.likely@secretlab.ca \
    --to=grant.likely@secretlab.ca \
    --cc=aliguori@us.ibm.com \
    --cc=edgar.iglesias@gmail.com \
    --cc=paul@codesourcery.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    /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 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).