From: lrg@slimlogic.co.uk (Liam Girdwood)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH] leds: Add LED class driver for regulator driven LEDs.
Date: Wed, 02 Dec 2009 18:23:55 +0000 [thread overview]
Message-ID: <1259778235.3588.141.camel@odin> (raw)
In-Reply-To: <1259775625-25973-1-git-send-email-ospite@studenti.unina.it>
On Wed, 2009-12-02 at 18:40 +0100, Antonio Ospite wrote:
> This driver provides an interface for controlling LEDs (or vibrators)
> connected to PMICs for which there is a regulator framework driver.
>
> This driver can be used, for instance, to control vibrator on all Motorola EZX
> phones using the pcap-regulator driver services.
>
> Signed-off-by: Antonio Ospite <ospite@studenti.unina.it>
Some very minor points below.
> ---
> The patch is against:
> git://git.o-hand.com/linux-rpurdie-leds for-mm
>
> A doubt I had was about leaving the 'supply' variable configurable from
> platform data, or relying on some fixed value like "vled", but leaving it
> configurable covers the case when we have different regulators used for
> different LEDs or vibrators.
>
> Should I add a note in Documentation/ about how to use it? Tell me if so.
>
> Thanks,
> Antonio
>
> P.S.: for those who get the mail from LKML, please Cc me on reply.
>
> drivers/leds/Kconfig | 6 +
> drivers/leds/Makefile | 1 +
> drivers/leds/leds-regulator.c | 214 ++++++++++++++++++++++++++++++++++++++++
> include/linux/leds-regulator.h | 20 ++++
> 4 files changed, 241 insertions(+), 0 deletions(-)
> create mode 100644 drivers/leds/leds-regulator.c
> create mode 100644 include/linux/leds-regulator.h
>
> diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
> index f12a996..8a0e1ec 100644
> --- a/drivers/leds/Kconfig
> +++ b/drivers/leds/Kconfig
> @@ -229,6 +229,12 @@ config LEDS_PWM
> help
> This option enables support for pwm driven LEDs
>
> +config LEDS_REGULATOR
> + tristate "REGULATOR driven LED support"
> + depends on LEDS_CLASS && REGULATOR
> + help
> + This option enables support for regulator driven LEDs.
> +
> config LEDS_BD2802
> tristate "LED driver for BD2802 RGB LED"
> depends on LEDS_CLASS && I2C
> diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
> index 176f0c6..9e63869 100644
> --- a/drivers/leds/Makefile
> +++ b/drivers/leds/Makefile
> @@ -29,6 +29,7 @@ obj-$(CONFIG_LEDS_DA903X) += leds-da903x.o
> obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o
> obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o
> obj-$(CONFIG_LEDS_PWM) += leds-pwm.o
> +obj-$(CONFIG_LEDS_REGULATOR) += leds-regulator.o
> obj-$(CONFIG_LEDS_INTEL_SS4200) += leds-ss4200.o
> obj-$(CONFIG_LEDS_LT3593) += leds-lt3593.o
> obj-$(CONFIG_LEDS_ADP5520) += leds-adp5520.o
> diff --git a/drivers/leds/leds-regulator.c b/drivers/leds/leds-regulator.c
> new file mode 100644
> index 0000000..fca5d42
> --- /dev/null
> +++ b/drivers/leds/leds-regulator.c
> @@ -0,0 +1,214 @@
> +/*
> + * leds-regulator.c - LED class driver for regulator driven LEDs.
> + *
> + * Copyright (C) 2009 Antonio Ospite <ospite@studenti.unina.it>
> + *
> + * Inspired by leds-wm8350 driver.
> + *
> + * 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/module.h>
> +#include <linux/err.h>
> +#include <linux/workqueue.h>
> +#include <linux/leds.h>
> +#include <linux/leds-regulator.h>
> +#include <linux/platform_device.h>
> +#include <linux/regulator/consumer.h>
> +
> +#define to_regulator_led(led_cdev) \
> + container_of(led_cdev, struct regulator_led, cdev)
> +
> +struct regulator_led {
> + struct led_classdev cdev;
> + enum led_brightness value;
> + int enabled;
> + struct mutex mutex;
> + struct work_struct work;
> +
> + struct regulator *vcc;
> +};
> +
> +static inline int led_regulator_get_max_brightness(struct regulator *supply)
> +{
> + return regulator_count_voltages(supply);
> +}
> +
> +static int led_regulator_get_vdd(struct regulator *supply,
> + enum led_brightness brightness)
> +{
> + if (brightness == 0)
> + return 0;
> +
> + return regulator_list_voltage(supply, brightness - 1);
> +}
> +
> +
> +static void regulator_led_enable(struct regulator_led *led)
> +{
> + int ret;
> +
> + if (led->enabled)
> + return;
> +
> + ret = regulator_enable(led->vcc);
> + if (ret != 0) {
> + dev_err(led->cdev.dev, "Failed to enable vcc: %d\n", ret);
> + return;
> + }
> +
> + led->enabled = 1;
> +}
> +
> +static void regulator_led_disable(struct regulator_led *led)
> +{
> + int ret;
> +
> + if (!led->enabled)
> + return;
> +
> + ret = regulator_disable(led->vcc);
> + if (ret != 0) {
> + dev_err(led->cdev.dev, "Failed to disable vcc: %d\n", ret);
> + return;
> + }
> +
> + led->enabled = 0;
> +}
> +
> +static void led_work(struct work_struct *work)
> +{
> + struct regulator_led *led;
> + int voltage;
> + int ret;
> +
> + led = container_of(work, struct regulator_led, work);
> +
> + mutex_lock(&led->mutex);
> +
> + if (led->value == 0) {
LED_OFF instead of 0 here ?
> + regulator_led_disable(led);
> + goto out;
> + }
> +
> + voltage = led_regulator_get_vdd(led->vcc, led->value);
> + dev_dbg(led->cdev.dev, "brightness: %d voltage: %d",
> + led->value, voltage);
> +
> + ret = regulator_set_voltage(led->vcc, voltage, voltage);
> + if (ret != 0)
> + dev_err(led->cdev.dev, "Failed to set voltage %d: %d\n",
> + voltage, ret);
Some regulators may not support voltage change (via hw design or
constraints) so set_voltage() will fail. We probably want to handle this
regulator type so we don't call set_voltage().
> +
> + regulator_led_enable(led);
> +
> +out:
> + mutex_unlock(&led->mutex);
> +}
> +
> +static void regulator_led_brightness_set(struct led_classdev *led_cdev,
> + enum led_brightness value)
> +{
> + struct regulator_led *led = to_regulator_led(led_cdev);
> +
> + led->value = value;
> + schedule_work(&led->work);
> +}
> +
> +static int regulator_led_probe(struct platform_device *pdev)
> +{
> + struct led_regulator_platform_data *pdata = pdev->dev.platform_data;
> + struct regulator_led *led;
> + struct regulator *vcc;
> + int ret;
> +
> + if (pdata == NULL) {
> + dev_err(&pdev->dev, "no platform data\n");
> + return -ENODEV;
> + }
> +
> + vcc = regulator_get(&pdev->dev, pdata->supply);
> + if (IS_ERR(vcc)) {
> + dev_err(&pdev->dev, "Cannot get vcc for %s\n", pdata->name);
> + return PTR_ERR(vcc);;
double ;; here
> + }
> +
> + led = kzalloc(sizeof(*led), GFP_KERNEL);
> + if (led == NULL) {
> + ret = -ENOMEM;
> + goto err_vcc;
> + }
> +
> + ret = led_regulator_get_max_brightness(vcc);
> + if (ret < 0)
> + goto err_led;
> +
> + led->cdev.max_brightness = ret;
> +
> + led->cdev.brightness_set = regulator_led_brightness_set;
> + led->cdev.name = pdata->name;
> + led->cdev.flags |= LED_CORE_SUSPENDRESUME;
> + led->enabled = regulator_is_enabled(vcc);
> + led->vcc = vcc;
> +
> + mutex_init(&led->mutex);
> + INIT_WORK(&led->work, led_work);
> +
> + led->value = LED_OFF;
> + platform_set_drvdata(pdev, led);
> +
> + ret = led_classdev_register(&pdev->dev, &led->cdev);
> + if (ret < 0) {
> + cancel_work_sync(&led->work);
> + goto err_led;
> + }
> +
> + return 0;
> +
> +err_led:
> + kfree(led);
> +err_vcc:
> + regulator_put(vcc);
> + return ret;
> +}
> +
> +static int regulator_led_remove(struct platform_device *pdev)
> +{
> + struct regulator_led *led = platform_get_drvdata(pdev);
> +
> + led_classdev_unregister(&led->cdev);
> + cancel_work_sync(&led->work);
> + regulator_led_disable(led);
> + regulator_put(led->vcc);
> + kfree(led);
> + return 0;
> +}
> +
> +static struct platform_driver regulator_led_driver = {
> + .driver = {
> + .name = "leds-regulator",
> + .owner = THIS_MODULE,
> + },
> + .probe = regulator_led_probe,
> + .remove = regulator_led_remove,
> +};
> +
> +static int __devinit regulator_led_init(void)
> +{
> + return platform_driver_register(®ulator_led_driver);
> +}
> +module_init(regulator_led_init);
> +
> +static void regulator_led_exit(void)
> +{
> + platform_driver_unregister(®ulator_led_driver);
> +}
> +module_exit(regulator_led_exit);
> +
> +MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>");
> +MODULE_DESCRIPTION("Regulator driven LED driver");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:leds-regulator");
> diff --git a/include/linux/leds-regulator.h b/include/linux/leds-regulator.h
> new file mode 100644
> index 0000000..a5850fd
> --- /dev/null
> +++ b/include/linux/leds-regulator.h
> @@ -0,0 +1,20 @@
> +/*
> + * leds-regulator.h - platform data structure for regulator driven LEDs.
> + *
> + * Copyright (C) 2009 Antonio Ospite <ospite@studenti.unina.it>
> + *
> + * 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.
> + *
> + */
> +
> +#ifndef __LINUX_LEDS_REGULATOR_H
> +#define __LINUX_LEDS_REGULATOR_H
> +
> +struct led_regulator_platform_data {
> + char *name; /* LED name as expected by LED class */
> + char *supply;
> +};
> +
> +#endif /* __LINUX_LEDS_REGULATOR_H */
WARNING: multiple messages have this Message-ID (diff)
From: Liam Girdwood <lrg@slimlogic.co.uk>
To: Antonio Ospite <ospite@studenti.unina.it>
Cc: Richard Purdie <rpurdie@rpsys.net>,
Mark Brown <broonie@opensource.wolfsonmicro.com>,
Daniel Ribeiro <drwyrm@gmail.com>,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
openezx-devel@lists.openezx.org
Subject: Re: [PATCH] leds: Add LED class driver for regulator driven LEDs.
Date: Wed, 02 Dec 2009 18:23:55 +0000 [thread overview]
Message-ID: <1259778235.3588.141.camel@odin> (raw)
In-Reply-To: <1259775625-25973-1-git-send-email-ospite@studenti.unina.it>
On Wed, 2009-12-02 at 18:40 +0100, Antonio Ospite wrote:
> This driver provides an interface for controlling LEDs (or vibrators)
> connected to PMICs for which there is a regulator framework driver.
>
> This driver can be used, for instance, to control vibrator on all Motorola EZX
> phones using the pcap-regulator driver services.
>
> Signed-off-by: Antonio Ospite <ospite@studenti.unina.it>
Some very minor points below.
> ---
> The patch is against:
> git://git.o-hand.com/linux-rpurdie-leds for-mm
>
> A doubt I had was about leaving the 'supply' variable configurable from
> platform data, or relying on some fixed value like "vled", but leaving it
> configurable covers the case when we have different regulators used for
> different LEDs or vibrators.
>
> Should I add a note in Documentation/ about how to use it? Tell me if so.
>
> Thanks,
> Antonio
>
> P.S.: for those who get the mail from LKML, please Cc me on reply.
>
> drivers/leds/Kconfig | 6 +
> drivers/leds/Makefile | 1 +
> drivers/leds/leds-regulator.c | 214 ++++++++++++++++++++++++++++++++++++++++
> include/linux/leds-regulator.h | 20 ++++
> 4 files changed, 241 insertions(+), 0 deletions(-)
> create mode 100644 drivers/leds/leds-regulator.c
> create mode 100644 include/linux/leds-regulator.h
>
> diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
> index f12a996..8a0e1ec 100644
> --- a/drivers/leds/Kconfig
> +++ b/drivers/leds/Kconfig
> @@ -229,6 +229,12 @@ config LEDS_PWM
> help
> This option enables support for pwm driven LEDs
>
> +config LEDS_REGULATOR
> + tristate "REGULATOR driven LED support"
> + depends on LEDS_CLASS && REGULATOR
> + help
> + This option enables support for regulator driven LEDs.
> +
> config LEDS_BD2802
> tristate "LED driver for BD2802 RGB LED"
> depends on LEDS_CLASS && I2C
> diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
> index 176f0c6..9e63869 100644
> --- a/drivers/leds/Makefile
> +++ b/drivers/leds/Makefile
> @@ -29,6 +29,7 @@ obj-$(CONFIG_LEDS_DA903X) += leds-da903x.o
> obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o
> obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o
> obj-$(CONFIG_LEDS_PWM) += leds-pwm.o
> +obj-$(CONFIG_LEDS_REGULATOR) += leds-regulator.o
> obj-$(CONFIG_LEDS_INTEL_SS4200) += leds-ss4200.o
> obj-$(CONFIG_LEDS_LT3593) += leds-lt3593.o
> obj-$(CONFIG_LEDS_ADP5520) += leds-adp5520.o
> diff --git a/drivers/leds/leds-regulator.c b/drivers/leds/leds-regulator.c
> new file mode 100644
> index 0000000..fca5d42
> --- /dev/null
> +++ b/drivers/leds/leds-regulator.c
> @@ -0,0 +1,214 @@
> +/*
> + * leds-regulator.c - LED class driver for regulator driven LEDs.
> + *
> + * Copyright (C) 2009 Antonio Ospite <ospite@studenti.unina.it>
> + *
> + * Inspired by leds-wm8350 driver.
> + *
> + * 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/module.h>
> +#include <linux/err.h>
> +#include <linux/workqueue.h>
> +#include <linux/leds.h>
> +#include <linux/leds-regulator.h>
> +#include <linux/platform_device.h>
> +#include <linux/regulator/consumer.h>
> +
> +#define to_regulator_led(led_cdev) \
> + container_of(led_cdev, struct regulator_led, cdev)
> +
> +struct regulator_led {
> + struct led_classdev cdev;
> + enum led_brightness value;
> + int enabled;
> + struct mutex mutex;
> + struct work_struct work;
> +
> + struct regulator *vcc;
> +};
> +
> +static inline int led_regulator_get_max_brightness(struct regulator *supply)
> +{
> + return regulator_count_voltages(supply);
> +}
> +
> +static int led_regulator_get_vdd(struct regulator *supply,
> + enum led_brightness brightness)
> +{
> + if (brightness == 0)
> + return 0;
> +
> + return regulator_list_voltage(supply, brightness - 1);
> +}
> +
> +
> +static void regulator_led_enable(struct regulator_led *led)
> +{
> + int ret;
> +
> + if (led->enabled)
> + return;
> +
> + ret = regulator_enable(led->vcc);
> + if (ret != 0) {
> + dev_err(led->cdev.dev, "Failed to enable vcc: %d\n", ret);
> + return;
> + }
> +
> + led->enabled = 1;
> +}
> +
> +static void regulator_led_disable(struct regulator_led *led)
> +{
> + int ret;
> +
> + if (!led->enabled)
> + return;
> +
> + ret = regulator_disable(led->vcc);
> + if (ret != 0) {
> + dev_err(led->cdev.dev, "Failed to disable vcc: %d\n", ret);
> + return;
> + }
> +
> + led->enabled = 0;
> +}
> +
> +static void led_work(struct work_struct *work)
> +{
> + struct regulator_led *led;
> + int voltage;
> + int ret;
> +
> + led = container_of(work, struct regulator_led, work);
> +
> + mutex_lock(&led->mutex);
> +
> + if (led->value == 0) {
LED_OFF instead of 0 here ?
> + regulator_led_disable(led);
> + goto out;
> + }
> +
> + voltage = led_regulator_get_vdd(led->vcc, led->value);
> + dev_dbg(led->cdev.dev, "brightness: %d voltage: %d",
> + led->value, voltage);
> +
> + ret = regulator_set_voltage(led->vcc, voltage, voltage);
> + if (ret != 0)
> + dev_err(led->cdev.dev, "Failed to set voltage %d: %d\n",
> + voltage, ret);
Some regulators may not support voltage change (via hw design or
constraints) so set_voltage() will fail. We probably want to handle this
regulator type so we don't call set_voltage().
> +
> + regulator_led_enable(led);
> +
> +out:
> + mutex_unlock(&led->mutex);
> +}
> +
> +static void regulator_led_brightness_set(struct led_classdev *led_cdev,
> + enum led_brightness value)
> +{
> + struct regulator_led *led = to_regulator_led(led_cdev);
> +
> + led->value = value;
> + schedule_work(&led->work);
> +}
> +
> +static int regulator_led_probe(struct platform_device *pdev)
> +{
> + struct led_regulator_platform_data *pdata = pdev->dev.platform_data;
> + struct regulator_led *led;
> + struct regulator *vcc;
> + int ret;
> +
> + if (pdata == NULL) {
> + dev_err(&pdev->dev, "no platform data\n");
> + return -ENODEV;
> + }
> +
> + vcc = regulator_get(&pdev->dev, pdata->supply);
> + if (IS_ERR(vcc)) {
> + dev_err(&pdev->dev, "Cannot get vcc for %s\n", pdata->name);
> + return PTR_ERR(vcc);;
double ;; here
> + }
> +
> + led = kzalloc(sizeof(*led), GFP_KERNEL);
> + if (led == NULL) {
> + ret = -ENOMEM;
> + goto err_vcc;
> + }
> +
> + ret = led_regulator_get_max_brightness(vcc);
> + if (ret < 0)
> + goto err_led;
> +
> + led->cdev.max_brightness = ret;
> +
> + led->cdev.brightness_set = regulator_led_brightness_set;
> + led->cdev.name = pdata->name;
> + led->cdev.flags |= LED_CORE_SUSPENDRESUME;
> + led->enabled = regulator_is_enabled(vcc);
> + led->vcc = vcc;
> +
> + mutex_init(&led->mutex);
> + INIT_WORK(&led->work, led_work);
> +
> + led->value = LED_OFF;
> + platform_set_drvdata(pdev, led);
> +
> + ret = led_classdev_register(&pdev->dev, &led->cdev);
> + if (ret < 0) {
> + cancel_work_sync(&led->work);
> + goto err_led;
> + }
> +
> + return 0;
> +
> +err_led:
> + kfree(led);
> +err_vcc:
> + regulator_put(vcc);
> + return ret;
> +}
> +
> +static int regulator_led_remove(struct platform_device *pdev)
> +{
> + struct regulator_led *led = platform_get_drvdata(pdev);
> +
> + led_classdev_unregister(&led->cdev);
> + cancel_work_sync(&led->work);
> + regulator_led_disable(led);
> + regulator_put(led->vcc);
> + kfree(led);
> + return 0;
> +}
> +
> +static struct platform_driver regulator_led_driver = {
> + .driver = {
> + .name = "leds-regulator",
> + .owner = THIS_MODULE,
> + },
> + .probe = regulator_led_probe,
> + .remove = regulator_led_remove,
> +};
> +
> +static int __devinit regulator_led_init(void)
> +{
> + return platform_driver_register(®ulator_led_driver);
> +}
> +module_init(regulator_led_init);
> +
> +static void regulator_led_exit(void)
> +{
> + platform_driver_unregister(®ulator_led_driver);
> +}
> +module_exit(regulator_led_exit);
> +
> +MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>");
> +MODULE_DESCRIPTION("Regulator driven LED driver");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:leds-regulator");
> diff --git a/include/linux/leds-regulator.h b/include/linux/leds-regulator.h
> new file mode 100644
> index 0000000..a5850fd
> --- /dev/null
> +++ b/include/linux/leds-regulator.h
> @@ -0,0 +1,20 @@
> +/*
> + * leds-regulator.h - platform data structure for regulator driven LEDs.
> + *
> + * Copyright (C) 2009 Antonio Ospite <ospite@studenti.unina.it>
> + *
> + * 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.
> + *
> + */
> +
> +#ifndef __LINUX_LEDS_REGULATOR_H
> +#define __LINUX_LEDS_REGULATOR_H
> +
> +struct led_regulator_platform_data {
> + char *name; /* LED name as expected by LED class */
> + char *supply;
> +};
> +
> +#endif /* __LINUX_LEDS_REGULATOR_H */
next prev parent reply other threads:[~2009-12-02 18:23 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-12-02 17:40 [PATCH] leds: Add LED class driver for regulator driven LEDs Antonio Ospite
2009-12-02 18:06 ` Mark Brown
2009-12-02 18:06 ` Mark Brown
2009-12-02 20:25 ` Antonio Ospite
2009-12-02 20:25 ` Antonio Ospite
2009-12-02 20:40 ` Mark Brown
2009-12-02 20:40 ` Mark Brown
2009-12-02 20:48 ` Antonio Ospite
2009-12-02 20:48 ` Antonio Ospite
2009-12-04 12:39 ` Antonio Ospite
2009-12-04 12:39 ` Antonio Ospite
2009-12-04 12:45 ` Mark Brown
2009-12-04 12:45 ` Mark Brown
2009-12-02 18:23 ` Liam Girdwood [this message]
2009-12-02 18:23 ` Liam Girdwood
2009-12-02 20:31 ` Antonio Ospite
2009-12-02 20:31 ` Antonio Ospite
2009-12-02 20:41 ` Mark Brown
2009-12-02 20:41 ` Mark Brown
2009-12-04 12:57 ` Antonio Ospite
2009-12-04 12:57 ` Antonio Ospite
2009-12-07 11:49 ` Mark Brown
2009-12-07 11:49 ` Mark Brown
2009-12-07 14:08 ` [PATCH v2] " Antonio Ospite
2009-12-15 10:22 ` Antonio Ospite
2009-12-15 10:22 ` Antonio Ospite
2009-12-15 10:58 ` Mark Brown
2009-12-15 10:58 ` Mark Brown
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=1259778235.3588.141.camel@odin \
--to=lrg@slimlogic.co.uk \
--cc=linux-arm-kernel@lists.infradead.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.