linux-omap.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Sebastian Reichel <sre@kernel.org>
To: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Cc: Tomi Valkeinen <tomi.valkeinen@ti.com>,
	Tony Lindgren <tony@atomide.com>,
	Merlijn Wajer <merlijn@wizzup.org>,
	"H. Nikolaus Schaller" <hns@goldelico.com>,
	Rob Herring <robh@kernel.org>,
	linux-omap@vger.kernel.org, dri-devel@lists.freedesktop.org,
	kernel@collabora.com
Subject: Re: [PATCHv2 08/56] drm/omap: panel-dsi-cm: convert to transfer API
Date: Wed, 26 Feb 2020 23:12:06 +0100	[thread overview]
Message-ID: <20200226221206.bazba2kia7hzani6@earth.universe> (raw)
In-Reply-To: <20200225145221.GG4764@pendragon.ideasonboard.com>

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

Hi,

On Tue, Feb 25, 2020 at 04:52:21PM +0200, Laurent Pinchart wrote:
> Hi Sebastian,
> 
> Thank you for the patch.
> 
> On Tue, Feb 25, 2020 at 12:20:38AM +0100, Sebastian Reichel wrote:
> > This converts the panel-dsi-cm driver to use the transfer
> > API instead of specific functions, so that the specific
> > functions can be unexported and squashed into the generic
> > transfer function.
> > 
> > Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
> > ---
> >  .../gpu/drm/omapdrm/displays/panel-dsi-cm.c   | 133 +++++++++++++-----
> >  1 file changed, 96 insertions(+), 37 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c
> > index e6ebfc35243e..92f510a771fe 100644
> > --- a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c
> > +++ b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c
> > @@ -140,45 +140,61 @@ static void hw_guard_wait(struct panel_drv_data *ddata)
> >  static int dsicm_dcs_read_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 *data)
> >  {
> >  	struct omap_dss_device *src = ddata->src;
> > -	int r;
> > -	u8 buf[1];
> > -
> > -	r = src->ops->dsi.dcs_read(src, ddata->channel, dcs_cmd, buf, 1);
> > -
> > -	if (r < 0)
> > -		return r;
> > -
> > -	*data = buf[0];
> > +	const struct mipi_dsi_msg msg = {
> > +		.channel = ddata->channel,
> > +		.type = MIPI_DSI_DCS_READ,
> > +		.tx_len = 1,
> > +		.tx_buf = &dcs_cmd,
> > +		.rx_len = 1,
> > +		.rx_buf = data
> > +	};
> >  
> > -	return 0;
> > +	return src->ops->dsi.transfer(src, &msg);
> >  }
> >  
> >  static int dsicm_dcs_write_0(struct panel_drv_data *ddata, u8 dcs_cmd)
> >  {
> >  	struct omap_dss_device *src = ddata->src;
> > +	const struct mipi_dsi_msg msg = {
> > +		.channel = ddata->channel,
> > +		.type = MIPI_DSI_DCS_SHORT_WRITE,
> > +		.tx_buf = &dcs_cmd,
> > +		.tx_len = 1,
> > +	};
> >  
> > -	return src->ops->dsi.dcs_write(src, ddata->channel, &dcs_cmd, 1);
> > +	return src->ops->dsi.transfer(src, &msg);
> >  }
> >  
> >  static int dsicm_dcs_write_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 param)
> >  {
> >  	struct omap_dss_device *src = ddata->src;
> > -	u8 buf[2] = { dcs_cmd, param };
> > +	const u8 buf[] = { dcs_cmd, param };
> > +	const struct mipi_dsi_msg msg = {
> > +		.channel = ddata->channel,
> > +		.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM,
> > +		.tx_buf = &buf,
> > +		.tx_len = 2,
> > +	};
> >  
> > -	return src->ops->dsi.dcs_write(src, ddata->channel, buf, 2);
> > +	return src->ops->dsi.transfer(src, &msg);
> >  }
> >  
> >  static int dsicm_sleep_in(struct panel_drv_data *ddata)
> >  
> >  {
> >  	struct omap_dss_device *src = ddata->src;
> > -	u8 cmd;
> >  	int r;
> > +	const u8 cmd = MIPI_DCS_ENTER_SLEEP_MODE;
> > +	const struct mipi_dsi_msg msg = {
> > +		.channel = ddata->channel,
> > +		.type = MIPI_DSI_DCS_SHORT_WRITE,
> > +		.tx_buf = &cmd,
> > +		.tx_len = 1,
> > +	};
> >  
> >  	hw_guard_wait(ddata);
> >  
> > -	cmd = MIPI_DCS_ENTER_SLEEP_MODE;
> > -	r = src->ops->dsi.dcs_write_nosync(src, ddata->channel, &cmd, 1);
> > +	r = src->ops->dsi.transfer(src, &msg);
> 
> Should you call dsicm_dcs_write_0(ddata, MIPI_DCS_ENTER_SLEEP_MODE)
> instead ? This uses the _nosync variant though, is it an issue ?

Right, this will be replaced by mipi_dsi_dcs_enter_sleep_mode() in
a future patch. I did not notice any issues with commands not being
send when panel is turned off, so it should be fine.

> >  	if (r)
> >  		return r;
> >  
> > @@ -233,28 +249,44 @@ static int dsicm_set_update_window(struct panel_drv_data *ddata,
> >  	u16 y1 = y;
> >  	u16 y2 = y + h - 1;
> >  
> > -	u8 buf[5];
> > -	buf[0] = MIPI_DCS_SET_COLUMN_ADDRESS;
> > -	buf[1] = (x1 >> 8) & 0xff;
> > -	buf[2] = (x1 >> 0) & 0xff;
> > -	buf[3] = (x2 >> 8) & 0xff;
> > -	buf[4] = (x2 >> 0) & 0xff;
> > +	const u8 paramX[] = {
> > +		MIPI_DCS_SET_COLUMN_ADDRESS,
> > +		(x1 >> 8) & 0xff,
> > +		(x1 >> 0) & 0xff,
> > +		(x2 >> 8) & 0xff,
> > +		(x2 >> 0) & 0xff,
> > +	};
> >  
> > -	r = src->ops->dsi.dcs_write_nosync(src, ddata->channel, buf, sizeof(buf));
> > -	if (r)
> > -		return r;
> > +	const struct mipi_dsi_msg msgX = {
> > +		.channel = ddata->channel,
> > +		.type = MIPI_DSI_GENERIC_LONG_WRITE,
> > +		.tx_buf = paramX,
> > +		.tx_len = 5,
> > +	};
> >  
> > -	buf[0] = MIPI_DCS_SET_PAGE_ADDRESS;
> > -	buf[1] = (y1 >> 8) & 0xff;
> > -	buf[2] = (y1 >> 0) & 0xff;
> > -	buf[3] = (y2 >> 8) & 0xff;
> > -	buf[4] = (y2 >> 0) & 0xff;
> > +	const u8 paramY[] = {
> > +		MIPI_DCS_SET_PAGE_ADDRESS,
> > +		(y1 >> 8) & 0xff,
> > +		(y1 >> 0) & 0xff,
> > +		(y2 >> 8) & 0xff,
> > +		(y2 >> 0) & 0xff,
> > +	};
> >  
> > -	r = src->ops->dsi.dcs_write_nosync(src, ddata->channel, buf, sizeof(buf));
> 
> Also replacing a _nosync variant here.
>
> > +	const struct mipi_dsi_msg msgY = {
> > +		.channel = ddata->channel,
> > +		.type = MIPI_DSI_GENERIC_LONG_WRITE,
> > +		.tx_buf = paramY,
> > +		.tx_len = 5,
> > +	};
> > +
> > +
> 
> A single blank line is enough.
> 
> > +	r = src->ops->dsi.transfer(src, &msgX);
> >  	if (r)
> >  		return r;
> >  
> > -	src->ops->dsi.bta_sync(src, ddata->channel);
> > +	r = src->ops->dsi.transfer(src, &msgY);
> 
> And here, you're replacing bta_sync. If I understand the code correctly,
> you're essentially removing an optimization, as each write will sync,
> right ? I'm fine with this change if we add the functionality back later
> in this series.

Yes, this is an optimization. X and Y will be sync'd together. This
is removed here, so that we can use the common helpers:
mipi_dsi_dcs_set_column_address() and mipi_dsi_dcs_set_page_address().

Actually those are also removed even further when the update
handling is moved to DSI encoder. It should be possible to
reintroduce it there without the need to expose the nosync
feature via DRM API.

> > +	if (r)
> > +		return r;
> >  
> >  	return r;
> >  }
> > @@ -991,6 +1023,27 @@ static int dsicm_get_te(struct omap_dss_device *dssdev)
> >  	return r;
> >  }
> >  
> > +static int dsicm_set_max_rx_packet_size(struct omap_dss_device *dssdev,
> > +                                        u16 size)
> 
> Please use tabs instead of spaces for indentation.

Ack.

> > +{
> > +	struct panel_drv_data *ddata = to_panel_data(dssdev);
> > +	struct omap_dss_device *src = ddata->src;
> > +
> > +	const u8 buf[] = {
> > +		size & 0xff,
> > +		size >> 8 & 0xff,
> > +	};
> > +
> > +	const struct mipi_dsi_msg msg = {
> > +		.channel = ddata->channel,
> > +		.type = MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE,
> > +		.tx_buf = buf,
> > +		.tx_len = 2,
> > +	};
> > +
> > +	return src->ops->dsi.transfer(src, &msg);
> > +}
> > +
> >  static int dsicm_memory_read(struct omap_dss_device *dssdev,
> >  		void *buf, size_t size,
> >  		u16 x, u16 y, u16 w, u16 h)
> > @@ -1031,17 +1084,23 @@ static int dsicm_memory_read(struct omap_dss_device *dssdev,
> >  
> >  	dsicm_set_update_window(ddata, x, y, w, h);
> >  
> > -	r = src->ops->dsi.set_max_rx_packet_size(src, ddata->channel, plen);
> > +	r = dsicm_set_max_rx_packet_size(dssdev, plen);
> >  	if (r)
> >  		goto err2;
> >  
> >  	while (buf_used < size) {
> >  		u8 dcs_cmd = first ? 0x2e : 0x3e;
> > +		const struct mipi_dsi_msg msg = {
> > +			.channel = ddata->channel,
> > +			.type = MIPI_DSI_DCS_READ,
> > +			.tx_buf = &dcs_cmd,
> > +			.tx_len = 1,
> > +			.rx_buf = buf + buf_used,
> > +			.rx_len = size - buf_used,
> > +		};
> >  		first = 0;
> >  
> > -		r = src->ops->dsi.dcs_read(src, ddata->channel, dcs_cmd,
> > -				buf + buf_used, size - buf_used);
> > -
> > +		r = src->ops->dsi.transfer(src, &msg);
> >  		if (r < 0) {
> >  			dev_err(dssdev->dev, "read error\n");
> >  			goto err3;
> > @@ -1065,7 +1124,7 @@ static int dsicm_memory_read(struct omap_dss_device *dssdev,
> >  	r = buf_used;
> >  
> >  err3:
> > -	src->ops->dsi.set_max_rx_packet_size(src, ddata->channel, 1);
> > +	dsicm_set_max_rx_packet_size(dssdev, 1);
> >  err2:
> >  	src->ops->dsi.bus_unlock(src);
> >  err1:
> 
> -- 
> Regards,
> 
> Laurent Pinchart

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

  reply	other threads:[~2020-02-26 22:12 UTC|newest]

Thread overview: 113+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-02-24 23:20 [PATCHv2 00/56] drm/omap: Convert DSI code to use drm_mipi_dsi and drm_panel Sebastian Reichel
2020-02-24 23:20 ` [PATCHv2 01/56] ARM: dts: omap: add channel to DSI panels Sebastian Reichel
2020-02-24 23:38   ` Laurent Pinchart
2020-02-25  0:01     ` Sebastian Reichel
2020-02-27 20:09   ` Sam Ravnborg
2020-02-24 23:20 ` [PATCHv2 02/56] ARM: dts: omap4-droid4: add panel compatible Sebastian Reichel
2020-02-24 23:37   ` Laurent Pinchart
2020-02-24 23:47     ` Tony Lindgren
2020-02-27 22:10       ` Laurent Pinchart
2020-02-28 15:34         ` Tony Lindgren
2020-02-24 23:57     ` Sebastian Reichel
2020-02-27 20:10   ` Sam Ravnborg
2020-02-24 23:20 ` [PATCHv2 03/56] Revert "drm/omap: dss: Remove unused omap_dss_device operations" Sebastian Reichel
2020-03-25 12:42   ` Tomi Valkeinen
2020-02-24 23:20 ` [PATCHv2 04/56] omap/drm: drop unused dsi.configure_pins Sebastian Reichel
2020-02-24 23:42   ` Laurent Pinchart
2020-02-26 21:28     ` Sebastian Reichel
2020-02-26 21:36       ` Laurent Pinchart
2020-02-26 22:25         ` Sebastian Reichel
2020-03-25 12:45   ` Tomi Valkeinen
2020-02-24 23:20 ` [PATCHv2 05/56] drm/omap: dsi: use MIPI_DSI_FMT_* instead of OMAP_DSS_DSI_FMT_* Sebastian Reichel
2020-02-25 13:58   ` Laurent Pinchart
2020-02-26 21:25     ` Sebastian Reichel
2020-03-25 12:52   ` Tomi Valkeinen
2020-02-24 23:20 ` [PATCHv2 06/56] drm/omap: constify write buffers Sebastian Reichel
2020-02-25 14:13   ` Laurent Pinchart
2020-03-25 12:53   ` Tomi Valkeinen
2020-02-24 23:20 ` [PATCHv2 07/56] drm/omap: dsi: add generic transfer function Sebastian Reichel
2020-02-25 14:16   ` Laurent Pinchart
2020-03-25 13:05   ` Tomi Valkeinen
2020-02-24 23:20 ` [PATCHv2 08/56] drm/omap: panel-dsi-cm: convert to transfer API Sebastian Reichel
2020-02-25 14:52   ` Laurent Pinchart
2020-02-26 22:12     ` Sebastian Reichel [this message]
2020-02-24 23:20 ` [PATCHv2 09/56] drm/omap: dsi: unexport specific data transfer functions Sebastian Reichel
2020-02-25 14:53   ` Laurent Pinchart
2020-02-24 23:20 ` [PATCHv2 10/56] drm/omap: dsi: drop virtual channel logic Sebastian Reichel
2020-02-25 15:01   ` Laurent Pinchart
2020-04-01 11:30     ` Tomi Valkeinen
2020-04-01 11:33       ` Laurent Pinchart
2020-04-01 11:43         ` Tomi Valkeinen
2020-02-24 23:20 ` [PATCHv2 11/56] drm/omap: dsi: simplify write function Sebastian Reichel
2020-02-25 15:31   ` Laurent Pinchart
2020-02-26 22:46     ` Sebastian Reichel
2020-02-26 22:48       ` Laurent Pinchart
2020-02-24 23:20 ` [PATCHv2 12/56] drm/omap: dsi: simplify read functions Sebastian Reichel
2020-02-25 16:20   ` Laurent Pinchart
2020-02-24 23:20 ` [PATCHv2 13/56] drm/omap: dsi: switch dsi_vc_send_long/short to mipi_dsi_msg Sebastian Reichel
2020-02-25 16:30   ` Laurent Pinchart
2020-02-26 23:34     ` Sebastian Reichel
2020-02-24 23:20 ` [PATCHv2 14/56] drm/omap: dsi: introduce mipi_dsi_host Sebastian Reichel
2020-02-24 23:20 ` [PATCHv2 15/56] drm/omap: panel-dsi-cm: use DSI helpers Sebastian Reichel
2020-02-24 23:20 ` [PATCHv2 16/56] drm/omap: dsi: request VC via mipi_dsi_attach Sebastian Reichel
2020-02-24 23:20 ` [PATCHv2 17/56] drm/omap: panel-dsi-cm: drop hardcoded VC Sebastian Reichel
2020-02-24 23:20 ` [PATCHv2 18/56] drm/omap: panel-dsi-cm: use common MIPI DCS 1.3 defines Sebastian Reichel
2020-04-01 12:09   ` Tomi Valkeinen
2020-02-24 23:20 ` [PATCHv2 19/56] drm/omap: dsi: drop unused memory_read() Sebastian Reichel
2020-02-24 23:20 ` [PATCHv2 20/56] drm/omap: dsi: drop unused get_te() Sebastian Reichel
2020-02-24 23:20 ` [PATCHv2 21/56] drm/omap: dsi: drop unused enable_te() Sebastian Reichel
2020-02-24 23:20 ` [PATCHv2 22/56] drm/omap: dsi: drop useless sync() Sebastian Reichel
2020-02-24 23:20 ` [PATCHv2 23/56] drm/omap: dsi: use pixel-format and mode from attach Sebastian Reichel
2020-02-24 23:20 ` [PATCHv2 24/56] drm/omap: panel-dsi-cm: use bulk regulator API Sebastian Reichel
2020-02-24 23:20 ` [PATCHv2 25/56] drm/omap: dsi: lp/hs switching support for transfer() Sebastian Reichel
2020-02-24 23:20 ` [PATCHv2 26/56] drm/omap: dsi: move TE GPIO handling into core Sebastian Reichel
2020-02-24 23:20 ` [PATCHv2 27/56] drm/omap: dsi: drop custom enable_te() API Sebastian Reichel
2020-02-24 23:20 ` [PATCHv2 28/56] drm/omap: dsi: do bus locking in host driver Sebastian Reichel
2020-02-24 23:20 ` [PATCHv2 29/56] drm/omap: dsi: untangle ulps ops from enable/disable Sebastian Reichel
2020-02-24 23:21 ` [PATCHv2 30/56] drm/dsi: add MIPI_DSI_MODE_ULPS_IDLE Sebastian Reichel
2020-02-24 23:21 ` [PATCHv2 31/56] drm/omap: dsi: do ULPS in host driver Sebastian Reichel
2020-02-24 23:21 ` [PATCHv2 32/56] drm/omap: dsi: move panel refresh function to host Sebastian Reichel
2020-02-24 23:21 ` [PATCHv2 33/56] drm/omap: dsi: Reverse direction of the DSS device enable/disable operations Sebastian Reichel
2020-02-24 23:21 ` [PATCHv2 34/56] drm/omap: dsi: drop custom panel capability support Sebastian Reichel
2020-02-24 23:21 ` [PATCHv2 35/56] drm/omap: dsi: convert to drm_panel Sebastian Reichel
2020-02-24 23:21 ` [PATCHv2 36/56] drm/omap: drop omapdss-boot-init Sebastian Reichel
2020-02-24 23:21 ` [PATCHv2 37/56] drm/omap: dsi: implement check timings Sebastian Reichel
2020-02-24 23:21 ` [PATCHv2 38/56] drm/omap: panel-dsi-cm: use DEVICE_ATTR_RO Sebastian Reichel
2020-02-24 23:21 ` [PATCHv2 39/56] drm/omap: panel-dsi-cm: support unbinding Sebastian Reichel
2020-02-24 23:21 ` [PATCHv2 40/56] drm/omap: panel-dsi-cm: fix remove() Sebastian Reichel
2020-02-24 23:21 ` [PATCHv2 41/56] drm/omap: dsi: return proper error code from dsi_update_all() Sebastian Reichel
2020-04-01 12:23   ` Tomi Valkeinen
2020-02-24 23:21 ` [PATCHv2 42/56] drm/omap: remove global dss_device variable Sebastian Reichel
2020-02-24 23:21 ` [PATCHv2 43/56] drm/omap: bind components with drm_device argument Sebastian Reichel
2020-02-27  0:32   ` Sebastian Reichel
2020-02-24 23:21 ` [PATCHv2 44/56] drm/panel: Move OMAP's DSI command mode panel driver Sebastian Reichel
2020-02-24 23:21 ` [PATCHv2 45/56] drm/omap: dsi: Register a drm_bridge Sebastian Reichel
2020-02-25 11:50   ` [PATCHv2.1 " Sebastian Reichel
2020-02-24 23:21 ` [PATCHv2 46/56] drm/omap: remove legacy DSS device operations Sebastian Reichel
2020-02-24 23:21 ` [PATCHv2 47/56] drm/omap: remove unused omap_connector Sebastian Reichel
2020-02-24 23:21 ` [PATCHv2 48/56] drm/omap: simplify omap_display_id Sebastian Reichel
2020-02-24 23:21 ` [PATCHv2 49/56] drm/omap: drop unused DSS next pointer Sebastian Reichel
2020-02-24 23:21 ` [PATCHv2 50/56] drm/omap: drop empty omap_encoder helper functions Sebastian Reichel
2020-02-24 23:21 ` [PATCHv2 51/56] drm/omap: drop DSS ops_flags Sebastian Reichel
2020-02-24 23:21 ` [PATCHv2 52/56] drm/omap: drop dssdev display field Sebastian Reichel
2020-02-24 23:21 ` [PATCHv2 53/56] drm/omap: simplify DSI manual update code Sebastian Reichel
2020-02-24 23:21 ` [PATCHv2 54/56] ARM: omap2plus_defconfig: Update for moved DSI command mode panel Sebastian Reichel
2020-02-24 23:21 ` [PATCHv2 55/56] drm/panel/panel-dsi-cm: support rotation property Sebastian Reichel
2020-02-24 23:21 ` [PATCHv2 56/56] ARM: dts: omap4-droid4: add panel orientation Sebastian Reichel
2020-02-25  0:10 ` [PATCHv2 00/56] drm/omap: Convert DSI code to use drm_mipi_dsi and drm_panel Tony Lindgren
2020-02-25  2:28   ` Sebastian Reichel
2020-02-25 15:42     ` Tony Lindgren
2020-02-25 23:01       ` Sebastian Reichel
2020-02-25 23:06         ` Laurent Pinchart
2020-02-25 23:09         ` Tony Lindgren
2020-02-25 23:52           ` Sebastian Reichel
2020-02-26 12:20             ` Tomi Valkeinen
2020-02-25 11:53 ` [PATCHv2 57/56] dt-bindings: display: panel-dsi-cm: convert to YAML Sebastian Reichel
2020-02-27 20:35   ` Sam Ravnborg
2020-02-27 22:08     ` Laurent Pinchart
2020-02-26 12:28 ` [PATCHv2 00/56] drm/omap: Convert DSI code to use drm_mipi_dsi and drm_panel Tomi Valkeinen
2020-02-27  0:28   ` Sebastian Reichel
2020-03-25 12:47 ` Tomi Valkeinen
2020-03-25 13:03   ` Laurent Pinchart
2020-04-01 12:43     ` Tomi Valkeinen
2020-06-25 13:07 ` H. Nikolaus Schaller

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=20200226221206.bazba2kia7hzani6@earth.universe \
    --to=sre@kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=hns@goldelico.com \
    --cc=kernel@collabora.com \
    --cc=laurent.pinchart@ideasonboard.com \
    --cc=linux-omap@vger.kernel.org \
    --cc=merlijn@wizzup.org \
    --cc=robh@kernel.org \
    --cc=tomi.valkeinen@ti.com \
    --cc=tony@atomide.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 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).