From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
To: Julien Stephan <jstephan@baylibre.com>
Cc: Phi-bang Nguyen <pnguyen@baylibre.com>,
Florian Sylvestre <fsylvestre@baylibre.com>,
Paul Elder <paul.elder@ideasonboard.com>,
Laurent Pinchart <laurent.pinchart@ideasonboard.com>,
Andy Hsieh <andy.hsieh@mediatek.com>,
Conor Dooley <conor+dt@kernel.org>,
devicetree@vger.kernel.org,
Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, linux-mediatek@lists.infradead.org,
linux-media@vger.kernel.org, Louis Kuo <louis.kuo@mediatek.com>,
Matthias Brugger <matthias.bgg@gmail.com>,
Mauro Carvalho Chehab <mchehab@kernel.org>,
Rob Herring <robh+dt@kernel.org>
Subject: Re: [PATCH v4 4/5] media: platform: mediatek: isp_30: add mediatek ISP3.0 camsv
Date: Thu, 11 Jan 2024 13:07:11 +0100 [thread overview]
Message-ID: <7643bfd6-5979-4ab4-bd8f-024417dc49ba@collabora.com> (raw)
In-Reply-To: <20240110141443.364655-5-jstephan@baylibre.com>
Il 10/01/24 15:14, Julien Stephan ha scritto:
> From: Phi-bang Nguyen <pnguyen@baylibre.com>
>
> This driver provides a path to bypass the SoC ISP so that image data
> coming from the SENINF can go directly into memory without any image
> processing. This allows the use of an external ISP.
>
> Signed-off-by: Phi-bang Nguyen <pnguyen@baylibre.com>
> Signed-off-by: Florian Sylvestre <fsylvestre@baylibre.com>
> [Paul Elder fix irq locking]
> Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
> Co-developed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Co-developed-by: Julien Stephan <jstephan@baylibre.com>
> Signed-off-by: Julien Stephan <jstephan@baylibre.com>
> ---
> MAINTAINERS | 1 +
> .../platform/mediatek/isp/isp_30/Kconfig | 19 +
> .../platform/mediatek/isp/isp_30/Makefile | 1 +
> .../mediatek/isp/isp_30/camsv/Makefile | 7 +
> .../mediatek/isp/isp_30/camsv/mtk_camsv.c | 328 ++++++++
> .../mediatek/isp/isp_30/camsv/mtk_camsv.h | 199 +++++
> .../isp/isp_30/camsv/mtk_camsv30_hw.c | 427 ++++++++++
> .../isp/isp_30/camsv/mtk_camsv30_regs.h | 60 ++
> .../isp/isp_30/camsv/mtk_camsv_video.c | 774 ++++++++++++++++++
> 9 files changed, 1816 insertions(+)
> create mode 100644 drivers/media/platform/mediatek/isp/isp_30/camsv/Makefile
> create mode 100644 drivers/media/platform/mediatek/isp/isp_30/camsv/mtk_camsv.c
> create mode 100644 drivers/media/platform/mediatek/isp/isp_30/camsv/mtk_camsv.h
> create mode 100644 drivers/media/platform/mediatek/isp/isp_30/camsv/mtk_camsv30_hw.c
> create mode 100644 drivers/media/platform/mediatek/isp/isp_30/camsv/mtk_camsv30_regs.h
> create mode 100644 drivers/media/platform/mediatek/isp/isp_30/camsv/mtk_camsv_video.c
>
..snip..
> diff --git a/drivers/media/platform/mediatek/isp/isp_30/camsv/mtk_camsv30_hw.c b/drivers/media/platform/mediatek/isp/isp_30/camsv/mtk_camsv30_hw.c
> new file mode 100644
> index 000000000000..3b8ccdab2af0
> --- /dev/null
> +++ b/drivers/media/platform/mediatek/isp/isp_30/camsv/mtk_camsv30_hw.c
> @@ -0,0 +1,427 @@
..snip..
> +
> +static int mtk_camsv30_probe(struct platform_device *pdev)
> +{
> + static const char * const clk_names[] = { "cam", "camtg", "camsv"};
> +
> + struct mtk_cam_dev *cam_dev;
> + struct device *dev = &pdev->dev;
> + int ret;
> + int i;
> +
> + if (!iommu_present(&platform_bus_type))
> + return -EPROBE_DEFER;
> +
> + cam_dev = devm_kzalloc(dev, sizeof(*cam_dev), GFP_KERNEL);
> + if (!cam_dev)
> + return -ENOMEM;
> +
> + cam_dev->conf = of_device_get_match_data(dev);
> + if (!cam_dev->conf)
> + return -ENODEV;
> +
> + cam_dev->dev = dev;
> + dev_set_drvdata(dev, cam_dev);
> +
> + cam_dev->regs = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(cam_dev->regs))
> + return dev_err_probe(dev, PTR_ERR(cam_dev->regs),
> + "failed to map register base\n");
> +
> +
> + cam_dev->regs_img0 = devm_platform_ioremap_resource(pdev, 1);
> +
> + if (IS_ERR(cam_dev->regs_img0))
> + return dev_err_probe(dev, PTR_ERR(cam_dev->regs_img0),
> + "failed to map img0 register base\n");
> +
> +
> + cam_dev->regs_tg = devm_platform_ioremap_resource(pdev, 2);
> + if (IS_ERR(cam_dev->regs_tg))
> + return dev_err_probe(dev, PTR_ERR(cam_dev->regs_tg),
> + "failed to map TG register base\n");
> +
> +
> + cam_dev->num_clks = ARRAY_SIZE(clk_names);
> + cam_dev->clks = devm_kcalloc(dev, cam_dev->num_clks,
> + sizeof(*cam_dev->clks), GFP_KERNEL);
> + if (!cam_dev->clks)
> + return -ENOMEM;
> +
> + for (i = 0; i < cam_dev->num_clks; ++i)
> + cam_dev->clks[i].id = clk_names[i];
> +
> + ret = devm_clk_bulk_get(dev, cam_dev->num_clks, cam_dev->clks);
> + if (ret)
> + return dev_err_probe(dev, ret, "failed to get clocks: %i\n", ret);
> +
> +
> + cam_dev->irq = platform_get_irq(pdev, 0);
> + ret = devm_request_irq(dev, cam_dev->irq,
> + isp_irq_camsv30, 0,
> + dev_name(dev), cam_dev);
> + if (ret != 0)
> + return dev_err_probe(dev, -ENODEV, "failed to request irq=%d\n",
> + cam_dev->irq);
> +
> + cam_dev->hw_functions = &mtk_camsv30_hw_functions;
> +
> + spin_lock_init(&cam_dev->irqlock);
> +
> + /* initialise runtime power management */
> + pm_runtime_set_autosuspend_delay(dev, MTK_CAMSV30_AUTOSUSPEND_DELAY_MS);
> + pm_runtime_use_autosuspend(dev);
> + pm_runtime_set_suspended(dev);
> + pm_runtime_enable(dev);
devm_pm_runtime_enable() ?
> +
> + /* Initialize the v4l2 common part */
> + return mtk_cam_dev_init(cam_dev);
> +}
> +
> +static int mtk_camsv30_remove(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct mtk_cam_dev *cam_dev = dev_get_drvdata(dev);
> +
> + mtk_cam_dev_cleanup(cam_dev);
> + pm_runtime_put_autosuspend(dev);
> + pm_runtime_disable(dev);
> +
> + return 0;
> +}
> +
> +static const struct dev_pm_ops mtk_camsv30_pm_ops = {
> + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
> + pm_runtime_force_resume)
> + SET_RUNTIME_PM_OPS(mtk_camsv30_runtime_suspend,
> + mtk_camsv30_runtime_resume, NULL)
> +};
> +
> +static const struct of_device_id mtk_camsv30_of_ids[] = {
> + { .compatible = "mediatek,mt8365-camsv", .data = &camsv30_conf },
> + { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, mtk_camsv30_of_ids);
> +
> +static struct platform_driver mtk_camsv30_driver = {
> + .probe = mtk_camsv30_probe,
> + .remove = mtk_camsv30_remove,
You definitely want to use void .remove_new() here
Cheers,
Angelo
WARNING: multiple messages have this Message-ID (diff)
From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
To: Julien Stephan <jstephan@baylibre.com>
Cc: Phi-bang Nguyen <pnguyen@baylibre.com>,
Florian Sylvestre <fsylvestre@baylibre.com>,
Paul Elder <paul.elder@ideasonboard.com>,
Laurent Pinchart <laurent.pinchart@ideasonboard.com>,
Andy Hsieh <andy.hsieh@mediatek.com>,
Conor Dooley <conor+dt@kernel.org>,
devicetree@vger.kernel.org,
Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, linux-mediatek@lists.infradead.org,
linux-media@vger.kernel.org, Louis Kuo <louis.kuo@mediatek.com>,
Matthias Brugger <matthias.bgg@gmail.com>,
Mauro Carvalho Chehab <mchehab@kernel.org>,
Rob Herring <robh+dt@kernel.org>
Subject: Re: [PATCH v4 4/5] media: platform: mediatek: isp_30: add mediatek ISP3.0 camsv
Date: Thu, 11 Jan 2024 13:07:11 +0100 [thread overview]
Message-ID: <7643bfd6-5979-4ab4-bd8f-024417dc49ba@collabora.com> (raw)
In-Reply-To: <20240110141443.364655-5-jstephan@baylibre.com>
Il 10/01/24 15:14, Julien Stephan ha scritto:
> From: Phi-bang Nguyen <pnguyen@baylibre.com>
>
> This driver provides a path to bypass the SoC ISP so that image data
> coming from the SENINF can go directly into memory without any image
> processing. This allows the use of an external ISP.
>
> Signed-off-by: Phi-bang Nguyen <pnguyen@baylibre.com>
> Signed-off-by: Florian Sylvestre <fsylvestre@baylibre.com>
> [Paul Elder fix irq locking]
> Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
> Co-developed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Co-developed-by: Julien Stephan <jstephan@baylibre.com>
> Signed-off-by: Julien Stephan <jstephan@baylibre.com>
> ---
> MAINTAINERS | 1 +
> .../platform/mediatek/isp/isp_30/Kconfig | 19 +
> .../platform/mediatek/isp/isp_30/Makefile | 1 +
> .../mediatek/isp/isp_30/camsv/Makefile | 7 +
> .../mediatek/isp/isp_30/camsv/mtk_camsv.c | 328 ++++++++
> .../mediatek/isp/isp_30/camsv/mtk_camsv.h | 199 +++++
> .../isp/isp_30/camsv/mtk_camsv30_hw.c | 427 ++++++++++
> .../isp/isp_30/camsv/mtk_camsv30_regs.h | 60 ++
> .../isp/isp_30/camsv/mtk_camsv_video.c | 774 ++++++++++++++++++
> 9 files changed, 1816 insertions(+)
> create mode 100644 drivers/media/platform/mediatek/isp/isp_30/camsv/Makefile
> create mode 100644 drivers/media/platform/mediatek/isp/isp_30/camsv/mtk_camsv.c
> create mode 100644 drivers/media/platform/mediatek/isp/isp_30/camsv/mtk_camsv.h
> create mode 100644 drivers/media/platform/mediatek/isp/isp_30/camsv/mtk_camsv30_hw.c
> create mode 100644 drivers/media/platform/mediatek/isp/isp_30/camsv/mtk_camsv30_regs.h
> create mode 100644 drivers/media/platform/mediatek/isp/isp_30/camsv/mtk_camsv_video.c
>
..snip..
> diff --git a/drivers/media/platform/mediatek/isp/isp_30/camsv/mtk_camsv30_hw.c b/drivers/media/platform/mediatek/isp/isp_30/camsv/mtk_camsv30_hw.c
> new file mode 100644
> index 000000000000..3b8ccdab2af0
> --- /dev/null
> +++ b/drivers/media/platform/mediatek/isp/isp_30/camsv/mtk_camsv30_hw.c
> @@ -0,0 +1,427 @@
..snip..
> +
> +static int mtk_camsv30_probe(struct platform_device *pdev)
> +{
> + static const char * const clk_names[] = { "cam", "camtg", "camsv"};
> +
> + struct mtk_cam_dev *cam_dev;
> + struct device *dev = &pdev->dev;
> + int ret;
> + int i;
> +
> + if (!iommu_present(&platform_bus_type))
> + return -EPROBE_DEFER;
> +
> + cam_dev = devm_kzalloc(dev, sizeof(*cam_dev), GFP_KERNEL);
> + if (!cam_dev)
> + return -ENOMEM;
> +
> + cam_dev->conf = of_device_get_match_data(dev);
> + if (!cam_dev->conf)
> + return -ENODEV;
> +
> + cam_dev->dev = dev;
> + dev_set_drvdata(dev, cam_dev);
> +
> + cam_dev->regs = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(cam_dev->regs))
> + return dev_err_probe(dev, PTR_ERR(cam_dev->regs),
> + "failed to map register base\n");
> +
> +
> + cam_dev->regs_img0 = devm_platform_ioremap_resource(pdev, 1);
> +
> + if (IS_ERR(cam_dev->regs_img0))
> + return dev_err_probe(dev, PTR_ERR(cam_dev->regs_img0),
> + "failed to map img0 register base\n");
> +
> +
> + cam_dev->regs_tg = devm_platform_ioremap_resource(pdev, 2);
> + if (IS_ERR(cam_dev->regs_tg))
> + return dev_err_probe(dev, PTR_ERR(cam_dev->regs_tg),
> + "failed to map TG register base\n");
> +
> +
> + cam_dev->num_clks = ARRAY_SIZE(clk_names);
> + cam_dev->clks = devm_kcalloc(dev, cam_dev->num_clks,
> + sizeof(*cam_dev->clks), GFP_KERNEL);
> + if (!cam_dev->clks)
> + return -ENOMEM;
> +
> + for (i = 0; i < cam_dev->num_clks; ++i)
> + cam_dev->clks[i].id = clk_names[i];
> +
> + ret = devm_clk_bulk_get(dev, cam_dev->num_clks, cam_dev->clks);
> + if (ret)
> + return dev_err_probe(dev, ret, "failed to get clocks: %i\n", ret);
> +
> +
> + cam_dev->irq = platform_get_irq(pdev, 0);
> + ret = devm_request_irq(dev, cam_dev->irq,
> + isp_irq_camsv30, 0,
> + dev_name(dev), cam_dev);
> + if (ret != 0)
> + return dev_err_probe(dev, -ENODEV, "failed to request irq=%d\n",
> + cam_dev->irq);
> +
> + cam_dev->hw_functions = &mtk_camsv30_hw_functions;
> +
> + spin_lock_init(&cam_dev->irqlock);
> +
> + /* initialise runtime power management */
> + pm_runtime_set_autosuspend_delay(dev, MTK_CAMSV30_AUTOSUSPEND_DELAY_MS);
> + pm_runtime_use_autosuspend(dev);
> + pm_runtime_set_suspended(dev);
> + pm_runtime_enable(dev);
devm_pm_runtime_enable() ?
> +
> + /* Initialize the v4l2 common part */
> + return mtk_cam_dev_init(cam_dev);
> +}
> +
> +static int mtk_camsv30_remove(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct mtk_cam_dev *cam_dev = dev_get_drvdata(dev);
> +
> + mtk_cam_dev_cleanup(cam_dev);
> + pm_runtime_put_autosuspend(dev);
> + pm_runtime_disable(dev);
> +
> + return 0;
> +}
> +
> +static const struct dev_pm_ops mtk_camsv30_pm_ops = {
> + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
> + pm_runtime_force_resume)
> + SET_RUNTIME_PM_OPS(mtk_camsv30_runtime_suspend,
> + mtk_camsv30_runtime_resume, NULL)
> +};
> +
> +static const struct of_device_id mtk_camsv30_of_ids[] = {
> + { .compatible = "mediatek,mt8365-camsv", .data = &camsv30_conf },
> + { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, mtk_camsv30_of_ids);
> +
> +static struct platform_driver mtk_camsv30_driver = {
> + .probe = mtk_camsv30_probe,
> + .remove = mtk_camsv30_remove,
You definitely want to use void .remove_new() here
Cheers,
Angelo
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
next prev parent reply other threads:[~2024-01-11 12:07 UTC|newest]
Thread overview: 82+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-01-10 14:14 [PATCH v4 0/5] Add Mediatek ISP3.0 Julien Stephan
2024-01-10 14:14 ` Julien Stephan
2024-01-10 14:14 ` [PATCH v4 1/5] dt-bindings: media: add mediatek ISP3.0 sensor interface Julien Stephan
2024-01-10 14:14 ` Julien Stephan
2024-01-11 8:15 ` Laurent Pinchart
2024-01-11 8:15 ` Laurent Pinchart
2024-01-12 7:32 ` Krzysztof Kozlowski
2024-01-12 7:32 ` Krzysztof Kozlowski
2024-06-07 8:52 ` Julien Stephan
2024-06-07 8:52 ` Julien Stephan
2024-06-07 14:41 ` Laurent Pinchart
2024-06-07 14:41 ` Laurent Pinchart
2024-06-10 7:54 ` Krzysztof Kozlowski
2024-06-10 7:54 ` Krzysztof Kozlowski
2024-06-10 8:54 ` Laurent Pinchart
2024-06-10 8:54 ` Laurent Pinchart
2024-06-10 10:18 ` Krzysztof Kozlowski
2024-06-10 10:18 ` Krzysztof Kozlowski
2024-06-10 16:10 ` Conor Dooley
2024-06-10 16:10 ` Conor Dooley
2024-06-10 16:19 ` Conor Dooley
2024-06-10 16:19 ` Conor Dooley
2024-06-10 7:39 ` Krzysztof Kozlowski
2024-06-10 7:39 ` Krzysztof Kozlowski
2024-01-10 14:14 ` [PATCH v4 2/5] dt-bindings: media: add mediatek ISP3.0 camsv Julien Stephan
2024-01-10 14:14 ` Julien Stephan
2024-01-12 7:34 ` Krzysztof Kozlowski
2024-01-12 7:34 ` Krzysztof Kozlowski
2024-01-12 7:41 ` Laurent Pinchart
2024-01-12 7:41 ` Laurent Pinchart
2024-01-12 7:49 ` Krzysztof Kozlowski
2024-01-12 7:49 ` Krzysztof Kozlowski
2024-01-10 14:14 ` [PATCH v4 3/5] media: platform: mediatek: isp_30: add mediatek ISP3.0 sensor interface Julien Stephan
2024-01-10 14:14 ` Julien Stephan
2024-01-11 2:46 ` CK Hu (胡俊光)
2024-01-11 2:46 ` CK Hu (胡俊光)
2024-01-11 12:04 ` AngeloGioacchino Del Regno
2024-01-11 12:04 ` AngeloGioacchino Del Regno
2024-02-12 15:07 ` Julien Stephan
2024-02-12 15:07 ` Julien Stephan
2024-06-10 14:39 ` Julien Stephan
2024-06-10 14:39 ` Julien Stephan
2024-06-12 8:06 ` AngeloGioacchino Del Regno
2024-06-14 10:38 ` Julien Stephan
2024-06-14 12:33 ` Laurent Pinchart
2024-06-14 14:14 ` Julien Stephan
2024-06-14 14:42 ` Laurent Pinchart
2024-06-14 14:54 ` Julien Stephan
2024-06-15 0:47 ` Laurent Pinchart
2024-07-04 13:41 ` Julien Stephan
2024-02-15 9:21 ` Sakari Ailus
2024-02-15 9:21 ` Sakari Ailus
2024-03-20 9:04 ` CK Hu (胡俊光)
2024-03-20 9:04 ` CK Hu (胡俊光)
2024-01-10 14:14 ` [PATCH v4 4/5] media: platform: mediatek: isp_30: add mediatek ISP3.0 camsv Julien Stephan
2024-01-10 14:14 ` Julien Stephan
2024-01-11 12:07 ` AngeloGioacchino Del Regno [this message]
2024-01-11 12:07 ` AngeloGioacchino Del Regno
2024-01-12 0:58 ` CK Hu (胡俊光)
2024-01-12 0:58 ` CK Hu (胡俊光)
2024-01-12 1:48 ` CK Hu (胡俊光)
2024-01-12 1:48 ` CK Hu (胡俊光)
2024-01-12 3:55 ` CK Hu (胡俊光)
2024-01-12 3:55 ` CK Hu (胡俊光)
2024-02-15 11:55 ` Sakari Ailus
2024-02-15 11:55 ` Sakari Ailus
2024-03-18 3:50 ` CK Hu (胡俊光)
2024-03-18 3:50 ` CK Hu (胡俊光)
2024-03-18 5:18 ` CK Hu (胡俊光)
2024-03-18 5:18 ` CK Hu (胡俊光)
2024-03-18 5:42 ` CK Hu (胡俊光)
2024-03-18 5:42 ` CK Hu (胡俊光)
2024-03-19 8:47 ` CK Hu (胡俊光)
2024-03-19 8:47 ` CK Hu (胡俊光)
2024-03-20 9:36 ` CK Hu (胡俊光)
2024-03-20 9:36 ` CK Hu (胡俊光)
2024-01-10 14:14 ` [PATCH v4 5/5] arm64: dts: mediatek: mt8365: Add support for camera Julien Stephan
2024-01-10 14:14 ` Julien Stephan
2024-01-11 8:32 ` Laurent Pinchart
2024-01-11 8:32 ` Laurent Pinchart
2024-01-11 8:08 ` [PATCH v4 0/5] Add Mediatek ISP3.0 Laurent Pinchart
2024-01-11 8:08 ` Laurent Pinchart
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=7643bfd6-5979-4ab4-bd8f-024417dc49ba@collabora.com \
--to=angelogioacchino.delregno@collabora.com \
--cc=andy.hsieh@mediatek.com \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=fsylvestre@baylibre.com \
--cc=jstephan@baylibre.com \
--cc=krzysztof.kozlowski+dt@linaro.org \
--cc=laurent.pinchart@ideasonboard.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=linux-mediatek@lists.infradead.org \
--cc=louis.kuo@mediatek.com \
--cc=matthias.bgg@gmail.com \
--cc=mchehab@kernel.org \
--cc=paul.elder@ideasonboard.com \
--cc=pnguyen@baylibre.com \
--cc=robh+dt@kernel.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 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.