All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 2/2] pxa/hx4700: Add Synaptics NavPoint (PXA27x SSP/SPI) driver
@ 2011-08-11 16:26 Paul Parsons
  2011-08-16  9:13 ` Marek Vasut
  0 siblings, 1 reply; 16+ messages in thread
From: Paul Parsons @ 2011-08-11 16:26 UTC (permalink / raw)
  To: linux-arm-kernel

Add support for the Synaptics NavPoint connected to a PXA27x SSP port in SPI
slave mode. The driver implements a simple navigation pad. The four raised dots
are mapped to UP/DOWN/LEFT/RIGHT buttons and the centre of the touchpad is
mapped to the ENTER button.

Signed-off-by: Paul Parsons <lost.distance@yahoo.com>
---

V2: Split into 2 parts for hx4700 specific code and navpoint driver. Added
GPIO23_SSP1_SCLK_IN and GPIO102_NAVPOINT_PWR to mfp-pxa27x.h. Replaced power
on/off callback with gpio number. Added msleep() to SSP port ready loop.

diff -uprN clean-3.0.1/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h linux-3.0.1/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h
--- clean-3.0.1/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h	2011-08-05 05:59:21.000000000 +0100
+++ linux-3.0.1/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h	2011-08-11 16:49:00.004450942 +0100
@@ -206,6 +206,7 @@
 #define GPIO113_I2S_SYSCLK	MFP_CFG_OUT(GPIO113, AF1, DRIVE_LOW)
 
 /* SSP 1 */
+#define GPIO23_SSP1_SCLK_IN	MFP_CFG_IN(GPIO23, AF2)
 #define GPIO23_SSP1_SCLK	MFP_CFG_OUT(GPIO23, AF2, DRIVE_LOW)
 #define GPIO29_SSP1_SCLK	MFP_CFG_IN(GPIO29, AF3)
 #define GPIO27_SSP1_SYSCLK	MFP_CFG_OUT(GPIO27, AF1, DRIVE_LOW)
@@ -434,6 +435,9 @@
 #define GPIO112_nMSINS		MFP_CFG_IN(GPIO112, AF2)
 #define GPIO32_MSSCLK		MFP_CFG_OUT(GPIO32, AF1, DRIVE_LOW)
 
+/* Touchpad Controller */
+#define GPIO102_NAVPOINT_PWR	MFP_CFG_OUT(GPIO102, AF0, DRIVE_LOW)
+
 /* commonly used pin configurations */
 #define GPIOxx_LCD_16BPP	\
 	GPIO58_LCD_LDD_0,	\
diff -uprN clean-3.0.1/drivers/input/mouse/Kconfig linux-3.0.1/drivers/input/mouse/Kconfig
--- clean-3.0.1/drivers/input/mouse/Kconfig	2011-08-05 05:59:21.000000000 +0100
+++ linux-3.0.1/drivers/input/mouse/Kconfig	2011-08-11 16:49:00.004450942 +0100
@@ -322,4 +322,14 @@ config MOUSE_SYNAPTICS_I2C
 	  To compile this driver as a module, choose M here: the
 	  module will be called synaptics_i2c.
 
+config MOUSE_NAVPOINT_PXA27x
+	bool "Synaptics NavPoint (PXA27x SSP/SPI)"
+	depends on PXA27x && PXA_SSP
+	help
+	  This option enables support for the Synaptics NavPoint connected to
+	  a PXA27x SSP port in SPI slave mode. The driver implements a simple
+	  navigation pad. The four raised dots are mapped to UP/DOWN/LEFT/RIGHT
+	  buttons and the centre of the touchpad is mapped to the ENTER button.
+	  Say Y to enable the Synaptics NavPoint on the HP iPAQ hx4700.
+
 endif
diff -uprN clean-3.0.1/drivers/input/mouse/Makefile linux-3.0.1/drivers/input/mouse/Makefile
--- clean-3.0.1/drivers/input/mouse/Makefile	2011-08-05 05:59:21.000000000 +0100
+++ linux-3.0.1/drivers/input/mouse/Makefile	2011-08-11 16:49:00.004450942 +0100
@@ -19,6 +19,7 @@ obj-$(CONFIG_MOUSE_RISCPC)		+= rpcmouse.
 obj-$(CONFIG_MOUSE_SERIAL)		+= sermouse.o
 obj-$(CONFIG_MOUSE_SYNAPTICS_I2C)	+= synaptics_i2c.o
 obj-$(CONFIG_MOUSE_VSXXXAA)		+= vsxxxaa.o
+obj-$(CONFIG_MOUSE_NAVPOINT_PXA27x)	+= navpoint.o
 
 psmouse-objs := psmouse-base.o synaptics.o
 
diff -uprN clean-3.0.1/drivers/input/mouse/navpoint.c linux-3.0.1/drivers/input/mouse/navpoint.c
--- clean-3.0.1/drivers/input/mouse/navpoint.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-3.0.1/drivers/input/mouse/navpoint.c	2011-08-11 16:50:35.093084330 +0100
@@ -0,0 +1,317 @@
+/*
+ *  Copyright (C) 2011 Paul Parsons <lost.distance@yahoo.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/input/navpoint.h>
+#include <linux/interrupt.h>
+#include <linux/pxa2xx_ssp.h>
+#include <linux/slab.h>
+
+/*
+ *	Synaptics NavPoint (PXA27x SSP/SPI) driver.
+ */
+
+struct driver_data {
+	struct ssp_device *ssp;
+	int		gpio;
+	struct input_dev *input;
+	int		index;
+	uint8_t		data[8];
+	int		pressed;	/* 1 = pressed, 0 = released */
+	unsigned	code;		/* Key code of the last key pressed */
+};
+
+static const u32 sscr0 = 0
+	| SSCR0_TUM		/* TIM = 1; No TUR interrupts */
+	| SSCR0_RIM		/* RIM = 1; No ROR interrupts */
+	| SSCR0_SSE		/* SSE = 1; SSP enabled */
+	| SSCR0_Motorola	/* FRF = 0; Motorola SPI */
+	| SSCR0_DataSize(16)	/* DSS = 15; Data size = 16-bit */
+	;
+static const u32 sscr1 = 0
+	| SSCR1_SCFR		/* SCFR = 1; SSPSCLK only during transfers */
+	| SSCR1_SCLKDIR		/* SCLKDIR = 1; Slave mode */
+	| SSCR1_SFRMDIR		/* SFRMDIR = 1; Slave mode */
+	| SSCR1_RWOT		/* RWOT = 1; Receive without transmit mode */
+	| SSCR1_RxTresh(1)	/* RFT = 0; Receive FIFO threshold = 1 */
+	| SSCR1_SPH		/* SPH = 1; SSPSCLK inactive 0.5 + 1 cycles */
+	| SSCR1_RIE		/* RIE = 1; Receive FIFO interrupt enabled */
+	;
+static const u32 sssr = 0
+	| SSSR_BCE		/* BCE = 1; Clear BCE */
+	| SSSR_TUR		/* TUR = 1; Clear TUR */
+	| SSSR_EOC		/* EOC = 1; Clear EOC */
+	| SSSR_TINT		/* TINT = 1; Clear TINT */
+	| SSSR_PINT		/* PINT = 1; Clear PINT */
+	| SSSR_ROR		/* ROR = 1; Clear ROR */
+	;
+
+/*
+ *	MEP Query $22: Touchpad Coordinate Range Query is not supported by
+ *	the NavPoint module, so sampled values provide the N/S/E/W limits.
+ */
+
+#define WEST	2416		/* 1/3 width */
+#define EAST	3904		/* 2/3 width */
+#define SOUTH	2480		/* 1/3 height */
+#define NORTH	3424		/* 2/3 height */
+
+static void navpoint_packet(void *dev)
+{
+	struct driver_data *drv_data;
+	int pressed;
+	unsigned x, y;
+	unsigned code;
+
+	drv_data = dev;
+
+	switch (drv_data->data[0]) {
+	case 0xff:	/* Garbage (packet?) between reset and Hello packet */
+	case 0x00:	/* Module 0, NULL packet */
+		break;
+	case 0x0e:	/* Module 0, Absolute packet */
+		pressed = (drv_data->data[1] & 0x01);
+		if ((drv_data->pressed ^ pressed) == 0)	/* No change */
+			break;
+		drv_data->pressed = pressed;
+		x = ((drv_data->data[2] & 0x1f) << 8) | drv_data->data[3];
+		y = ((drv_data->data[4] & 0x1f) << 8) | drv_data->data[5];
+		if (x < WEST)
+			code = KEY_LEFT;
+		else if (x > EAST)
+			code = KEY_RIGHT;
+		else if (y < SOUTH)
+			code = KEY_DOWN;
+		else if (y > NORTH)
+			code = KEY_UP;
+		else
+			code = KEY_ENTER;
+		if (pressed)
+			drv_data->code = code;
+		input_report_key(drv_data->input, drv_data->code, pressed);
+		input_sync(drv_data->input);
+		break;
+	case 0x19:	/* Module 0, Hello packet */
+		if ((drv_data->data[1] & 0xf0) == 0x10)
+			break;
+		/* FALLTHROUGH */
+	default:
+		dev_warn(dev, "spurious packet: 0x%02x,0x%02x,...\n",
+			drv_data->data[0],
+			drv_data->data[1]);
+		break;
+	}
+
+	drv_data->index = 0;
+}
+
+static irqreturn_t navpoint_int(int irq, void *dev)
+{
+	struct driver_data *drv_data;
+	struct ssp_device *ssp;
+	u32 status;
+	irqreturn_t ret;
+
+	drv_data = dev;
+	ssp = drv_data->ssp;
+
+	status = pxa_ssp_read_reg(ssp, SSSR);
+	ret = (status & (sssr | SSSR_RFS)) ? IRQ_HANDLED : IRQ_NONE;
+
+	if (status & sssr) {
+		dev_warn(dev, "spurious interrupt: 0x%02x\n", status);
+		pxa_ssp_write_reg(ssp, SSSR, (status & sssr));
+	}
+
+	while (status & SSSR_RNE) {
+		u32 data;
+
+		data = pxa_ssp_read_reg(ssp, SSDR);
+		drv_data->data[drv_data->index + 0] = (data >> 8);
+		drv_data->data[drv_data->index + 1] = data;
+		drv_data->index += 2;
+		if ((drv_data->data[0] & 0x07) < drv_data->index)
+			navpoint_packet(dev);
+		status = pxa_ssp_read_reg(ssp, SSSR);
+	}
+
+	return ret;
+}
+
+#ifdef CONFIG_SUSPEND
+int navpoint_suspend(struct device *dev)
+{
+	struct driver_data *drv_data;
+	struct ssp_device *ssp;
+
+	drv_data = dev_get_drvdata(dev);
+	ssp = drv_data->ssp;
+
+	if (drv_data->gpio)
+		gpio_set_value(drv_data->gpio, 0);
+
+	pxa_ssp_write_reg(ssp, SSCR0, 0);
+
+	clk_disable(ssp->clk);
+
+	return 0;
+}
+
+int navpoint_resume(struct device *dev)
+{
+	struct driver_data *drv_data;
+	struct ssp_device *ssp;
+
+	drv_data = dev_get_drvdata(dev);
+	ssp = drv_data->ssp;
+
+	clk_enable(ssp->clk);
+
+	pxa_ssp_write_reg(ssp, SSCR1, sscr1);
+	pxa_ssp_write_reg(ssp, SSSR, sssr);
+	pxa_ssp_write_reg(ssp, SSTO, 0);
+	pxa_ssp_write_reg(ssp, SSCR0, sscr0);	/* SSCR0_SSE written last */
+
+	if (drv_data->gpio)
+		gpio_set_value(drv_data->gpio, 1);
+
+	/* Wait until SSP port is ready for slave clock operations */
+	while (pxa_ssp_read_reg(ssp, SSSR) & SSSR_CSS)
+		msleep(1);
+
+	return 0;
+}
+
+static const struct dev_pm_ops navpoint_pm_ops = {
+	.suspend	= navpoint_suspend,
+	.resume		= navpoint_resume,
+};
+#endif
+
+static int __devinit navpoint_probe(struct platform_device *pdev)
+{
+	struct navpoint_platform_data *pdata = pdev->dev.platform_data;
+	int ret;
+	struct driver_data *drv_data;
+	struct ssp_device *ssp;
+	struct input_dev *input;
+
+	drv_data = kzalloc(sizeof(struct driver_data), GFP_KERNEL);
+	if (!drv_data) {
+		ret = -ENOMEM;
+		goto ret0;
+	}
+
+	ssp = pxa_ssp_request(pdata->port, pdev->name);
+	if (!ssp) {
+		ret = -ENODEV;
+		goto ret1;
+	}
+
+	ret = request_irq(ssp->irq, navpoint_int, 0, pdev->name, drv_data);
+	if (ret)
+		goto ret2;
+
+	input = input_allocate_device();
+	if (!input) {
+		ret = -ENOMEM;
+		goto ret3;
+	}
+	input->name = pdev->name;
+	__set_bit(EV_KEY, input->evbit);
+	__set_bit(KEY_ENTER, input->keybit);
+	__set_bit(KEY_UP, input->keybit);
+	__set_bit(KEY_LEFT, input->keybit);
+	__set_bit(KEY_RIGHT, input->keybit);
+	__set_bit(KEY_DOWN, input->keybit);
+	input->dev.parent = &pdev->dev;
+	ret = input_register_device(input);
+	if (ret)
+		goto ret4;
+
+	drv_data->ssp = ssp;
+	drv_data->gpio = pdata->gpio;
+	drv_data->input = input;
+
+	platform_set_drvdata(pdev, drv_data);
+
+	(void) navpoint_resume(&pdev->dev);
+
+	dev_info(&pdev->dev, "ssp%d, irq %d\n", pdata->port, ssp->irq);
+
+	return 0;
+
+ret4:
+	input_free_device(input);
+ret3:
+	free_irq(ssp->irq, drv_data);
+ret2:
+	pxa_ssp_free(ssp);
+ret1:
+	kfree(drv_data);
+ret0:
+	return ret;
+}
+
+static int __devexit navpoint_remove(struct platform_device *pdev)
+{
+	struct driver_data *drv_data;
+	struct ssp_device *ssp;
+	struct input_dev *input;
+
+	drv_data = platform_get_drvdata(pdev);
+	ssp = drv_data->ssp;
+	input = drv_data->input;
+
+	(void) navpoint_suspend(&pdev->dev);
+
+	input_unregister_device(input);
+
+	free_irq(ssp->irq, drv_data);
+
+	pxa_ssp_free(ssp);
+
+	kfree(drv_data);
+
+	return 0;
+}
+
+static struct platform_driver navpoint_driver = {
+	.probe		= navpoint_probe,
+	.remove		= __devexit_p(navpoint_remove),
+	.driver = {
+		.name	= "navpoint",
+		.owner	= THIS_MODULE,
+#ifdef CONFIG_SUSPEND
+		.pm	= &navpoint_pm_ops,
+#endif
+	},
+};
+
+static int __init navpoint_init(void)
+{
+	return platform_driver_register(&navpoint_driver);
+}
+
+static void __exit navpoint_exit(void)
+{
+	platform_driver_unregister(&navpoint_driver);
+}
+
+module_init(navpoint_init);
+module_exit(navpoint_exit);
+
+MODULE_AUTHOR("Paul Parsons <lost.distance@yahoo.com>");
+MODULE_DESCRIPTION("Synaptics NavPoint (PXA27x SSP/SPI) driver");
+MODULE_LICENSE("GPL");
diff -uprN clean-3.0.1/include/linux/input/navpoint.h linux-3.0.1/include/linux/input/navpoint.h
--- clean-3.0.1/include/linux/input/navpoint.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-3.0.1/include/linux/input/navpoint.h	2011-08-11 16:50:50.761188696 +0100
@@ -0,0 +1,12 @@
+/*
+ *  Copyright (C) 2011 Paul Parsons <lost.distance@yahoo.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+
+struct navpoint_platform_data {
+	int		port;		/* PXA SSP port for pxa_ssp_request() */
+	int		gpio;		/* GPIO for power on/off */
+};

^ permalink raw reply	[flat|nested] 16+ messages in thread
* Re: [PATCH v2 2/2] pxa/hx4700: Add Synaptics NavPoint (PXA27x SSP/SPI) driver
@ 2011-08-14 10:31 Paul Parsons
  2011-08-15  8:01   ` Eric Miao
  2011-08-16  7:56   ` Igor Grinberg
  0 siblings, 2 replies; 16+ messages in thread
From: Paul Parsons @ 2011-08-14 10:31 UTC (permalink / raw)
  To: Igor Grinberg
  Cc: linux-arm-kernel, koen, eric.y.miao, philipp.zabel, mad_soft,
	Dmitry Torokhov, linux-input@vger.kernel.org

Hi Igor,

Thanks for reviewing the driver. Specific responses below.

    This patch should be 1/n as the other patches depend on it,
    should not include the mfp stuff and should be sent also to
    linux-input list
    and the input subsystem maintainer (both added to CC).

OK, will do.

+/* Touchpad Controller */
+#define GPIO102_NAVPOINT_PWR    MFP_CFG_OUT(GPIO102, AF0, DRIVE_LOW)
+

    The name is not generic, so IMO can't be placed in the generic file.
    Can't you use the already existing GPIO102_GPIO macro
    and then change the direction in the board or driver file?

MFP_CFG_OUT(GPIO102, ...) had already moved from the patch v1 platform file to patch v2 mfp-pxa27x.h because it was suggested that MFP macros should not be used directly.
Changing the direction in the platform file would surely require using the MFP macros again, so how to keep everyone happy? Maybe I should just define a more generic name such as GPIO102_GPIO_OUT?
    
+config MOUSE_NAVPOINT_PXA27x
+    bool "Synaptics NavPoint (PXA27x SSP/SPI)"
+    depends on PXA27x && PXA_SSP
+    help
+      This option enables support for the Synaptics NavPoint connected to
+      a PXA27x SSP port in SPI slave mode. The driver implements a simple
+      navigation pad. The four raised dots are mapped to UP/DOWN/LEFT/RIGHT
+      buttons and the centre of the touchpad is mapped to the ENTER button.
+      Say Y to enable the Synaptics NavPoint on the HP iPAQ hx4700.

    There is no direct dependency for HP iPAQ hx4700,
    so in theory each board that want to use it can use it.
    I'd remove the "on the HP iPAQ ..." from the above sentence.

I copied that wording from my earlier ASIC3 LED driver. I suppose my feeling was that it seemed unlikely that any other platform would ever use this driver (otherwise I wouldn't be the first to write it). I'm happy to remove it.
    
+obj-$(CONFIG_MOUSE_NAVPOINT_PXA27x)    += navpoint.o
 
    This does not look like mouse device... Why place it in the mouse
    directory?
    I think the most reasonable place would be drivers/input/keyboard

Because the underlying hardware is a touchpad controller and most of the touchpad drivers live in the mouse directory. I could have added a mouse interface to this driver but chose not to (at least for now) because the hx4700 platform already has a working touchscreen controller; a second mouse device was not needed. If future platforms require a mouse interface then one could be added relatively easily; surely this would be preferable to replicating the whole driver.

+struct driver_data {
+    struct ssp_device *ssp;
+    int        gpio;
+    struct input_dev *input;
+    int        index;
+    uint8_t        data[8];
+    int        pressed;    /* 1 = pressed, 0 = released */
+    unsigned    code;        /* Key code of the last key pressed */

    Why do you need it?

The code field? To match a button release with a button press. See later.
    
+#define WEST    2416        /* 1/3 width */
+#define EAST    3904        /* 2/3 width */
+#define SOUTH    2480        /* 1/3 height */
+#define NORTH    3424        /* 2/3 height */

    May be supply those via the platform_data?

OK, will do.

+    drv_data = dev;

    Can be done in the declaration line.

OK.

+        if (pressed)
+            drv_data->code = code;

    Why do you need to store the code? You don't use it in any place...

I use it in the next line. The store is conditional whereas the read is unconditional. That's why I need to store it.

+    drv_data = dev;

    This can be done in the declaration line.

OK.

+    status = pxa_ssp_read_reg(ssp, SSSR);
+    ret = (status & (sssr | SSSR_RFS)) ? IRQ_HANDLED : IRQ_NONE;
+
+    if (status & sssr) {
+        dev_warn(dev, "spurious interrupt: 0x%02x\n", status);
+        pxa_ssp_write_reg(ssp, SSSR, (status & sssr));
+    }
+
+    while (status & SSSR_RNE) {
+        u32 data;
+
+        data = pxa_ssp_read_reg(ssp, SSDR);
+        drv_data->data[drv_data->index + 0] = (data >> 8);
+        drv_data->data[drv_data->index + 1] = data;
+        drv_data->index += 2;
+        if ((drv_data->data[0] & 0x07) < drv_data->index)
+            navpoint_packet(dev);
+        status = pxa_ssp_read_reg(ssp, SSSR);
+    }

    Should all this really be done in the interrupt context?

Yes. The FIFO controller triggers a CPU interrupt when the number of RX FIFO entries >= SSCR1.RFT (RX FIFO threshold), which I have set to 1. If I don't drain the RX FIFO then the interrupt source will not be cleared and the interrupt handler will be re-entered immediately (I have verified this). In short, draining the RX FIFO clears the interrupt.

+    drv_data = dev_get_drvdata(dev);
+    ssp = drv_data->ssp;

    The above two can be done in the declaration line...

OK.

+    drv_data = dev_get_drvdata(dev);
+    ssp = drv_data->ssp;

    The above two can be done in the declaration line...

OK.

+    drv_data->gpio = pdata->gpio;

    I'd suggest checking if the supplied gpio is valid
    and also may be configure it for output?

The suspend and resume functions check that the gpio is valid (which is taken to be non-zero) before using it. The platform file has already configured the gpio for output; it's the GPIO102 discussed earlier.

+    (void) navpoint_resume(&pdev->dev);

    Will this compile if !CONFIG_SUSPEND?

oops. OK.

+    drv_data = platform_get_drvdata(pdev);
+    ssp = drv_data->ssp;
+    input = drv_data->input;

    You need neither ssp nor input variables - you only use them once.
    This will remove 4 lines...

Actually the ssp variable is used twice. Regardless, by declaring those two variables I ensured that most of navpoint_remove() was identical to the error return of navpoint_probe(). I suppose I value consistency more than saving lines. I'm happy to move those two assignments to the declaration line.

+    (void) navpoint_suspend(&pdev->dev);

    and will this compile if !CONFIG_SUSPEND?

oops again. OK.

Regards,
Paul
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

end of thread, other threads:[~2011-08-17  0:20 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-08-11 16:26 [PATCH v2 2/2] pxa/hx4700: Add Synaptics NavPoint (PXA27x SSP/SPI) driver Paul Parsons
2011-08-16  9:13 ` Marek Vasut
2011-08-16 14:21   ` Paul Parsons
2011-08-16 15:13     ` Marek Vasut
2011-08-17  0:20       ` Paul Parsons
  -- strict thread matches above, loose matches on Subject: below --
2011-08-14 10:31 Paul Parsons
2011-08-15  8:01 ` Eric Miao
2011-08-15  8:01   ` Eric Miao
2011-08-15  9:49   ` Paul Parsons
2011-08-15  9:49     ` Paul Parsons
2011-08-15  9:53     ` Eric Miao
2011-08-15  9:53       ` Eric Miao
2011-08-16  7:56 ` Igor Grinberg
2011-08-16  7:56   ` Igor Grinberg
2011-08-16 11:54   ` Paul Parsons
2011-08-16 11:54     ` Paul Parsons

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.